1. 基于深度学习的python速通(一)
  2. 基于深度学习的python速通(三)
  3. 基于深度学习的python速通(二)

数组基础

导入Numpy时,通常给其一个别名,即import numpy as np

数据类型

整数型数组与浮点型数组

为克服列表的缺点,一个Numpy数组只容纳一种数据类型,以节约内存。方便起见,可将Numpy数组简单分为整数型数组与浮点型数组。

1
2
3
4
5
6
7
8
import numpy as np
# 创建整数型数组
arr1 = np.array([1, 2, 3])
# 创建浮点型数组(内含浮点数则为浮点型)
arr2 = np.array([1.0, 2.0, 3.0])
# 查看数组数据类型
print(arr1.dtype) # int32
print(arr2.dtype) # float64

注意到,使用print输出Numpy数组后,元素之间没有逗号,这有两个好处:

  1. 可以与python列表区分开
  2. 避免逗号与小数点混淆

同化定理

  • 往整数型数组里插入浮点数,该浮点数会自动被截断为整数
  • 往浮点型数组里插入整数,该整数会自动被转换为浮点数
1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
# 整数型数组
arr1 = np.array([1, 2, 3])
# 浮点型数组
arr2 = np.array([1.0, 2.0, 3.0])
# 往整数型数组里插入浮点数
arr1[0] = 5.5
print(arr1) # [1 2 3]
# 往浮点型数组里插入整数
arr2[0] = 100
print(arr2) # [1. 2. 3.]
>(5 2 3)
>(100.0 2.0 3.0)

共同改变定理

同化定理说明整数型数组和浮点型数组之间的界限十分严格,那么如何将这两组数据类型的数组互相转化?

  • 整数型数组转换为浮点型数组:使用astype方法
  • 浮点型数组转换为整数型数组:使用astype方法
1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np
# 整数型数组
arr1 = np.array([1, 2, 3])
# 浮点型数组
arr2 = np.array([1.0, 2.0, 3.0])
# 整数型数组转换为浮点型数组
arr1 = arr1.astype(float)
print(arr1) # [1. 2. 3.]
# 浮点型数组转换为整数型数组
arr2 = arr2.astype(int)
print(arr2) # [1 2 3]
>(1 2 3)
>(1.0 2.0 3.0)

除上述方法,只要阿玛尼组共同改变定理,整数型数组和浮点型数组仍然可以互相转化,最常见的是整数型数组在运算过程中升级为浮点型数组,这在深度学习中非常常见。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
# 整数型数组
arr = np.array([1,2,3])
print(arr + 0.0)
print(arr * 1.0)
>(1.0 2.0 3.0)
>(1.0 2.0 3.0)
# 整数型数组除法运算(即使除以整数仍会转化为浮点数)
print(arr/1)
>(1.0 2.0 3.0)
# 整数型数组与浮点型数组做运算
int_arr = np.array([1,2,3])
float_arr = np.array([1.0,2.0,3.0])
print(int_arr + float_arr)
>(2.0 4.0 6.0)

整数型数组很好升级,但浮点型数组在运算过程中一般不会降级

数组维度

一维数组与二维数组

考虑到深度学习中三维及其以上数组出现次数较少,后续主要学习Numpy中的一维数组和二维数组,一二维数组可以类推三维数组

  • 不同维度数组之间,从外形上的本质区别是
    • 一维数组使用1层中括号
    • 二维数组使用2层中括号
    • 三维数组使用3层中括号
  • 有些函数需要传入数组的形状参数,不同维度数组的形状参数为
    • 一维数组:(n,)
    • 二维数组:(n,m)
    • 三维数组:(n,m,k)
  • 现在以同一个序列进行举例
    • 当数组有1层中括号,如[1 2 3],则其为一维数组,其形状是3或(3,)
    • 当数组有两层中括号,如[[1 2 3]],则其为二维数组,其形状是(1,3)(一行三列)
    • 当数组有三层中括号,如[[[1 2 3]]],则其为三维数组,其形状是(1,1,3)(一个1x1的矩阵,每个元素是一个长度为3的向量)
1
2
3
4
5
6
7
8
9
arr1 = np.ones((3,))
arr2 = np.ones((1,3))
arr3 = np.ones((1,1,3))
print(arr1.shape)
print(arr2.shape)
print(arr3.shape)
>(3,)
>(1, 3)
>(1, 1, 3)

不同维度数组之间的转换

一维数组转二维数组,还是二维数组转一维数组,均要使用数组的重塑方法reshape,该方法需要传入重塑后的形状参数
这个方法给定其他维度的数值,剩下的一个维度可以填-1,让Numpy自动计算该维度的数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
# 一维数组转二维数组
arr1 = np.array([1,2,3])
arr2 = arr1.reshape((1,3))
print(arr2)
>(1 2 3)
>([[1 2 3]])
# 二维数组转一维数组
arr3 = np.arange(10).reshape(2,5)
arr4 = arr3.reshape(-1)
print(arr3)
print(arr4)
>[[0 2 3 4 ]
[5 6 7 8 9]]
>[0 1 2 3 4 5 6 7 8 9]

数组的创建

创建指定数组

当明确知道数组的每一个元素时,可以使用np.array()方法将Python列表转化为Numpy数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
# 创建一维数组————向量
arr1 = np.array([1,2,3])
print(arr1)
# 创建二维数组————行矩阵
arr2 = np.array([[1,2,3]])
print(arr2)
# 创建二维数组————列矩阵
arr3 = np.array([[1],[2],[3]])
print(arr3)
# 创建二维数组————矩阵
arr4 = np.array([[1,2,3],[4,5,6]])
>[1 2 3]
>([[1 2 3]])
>([[1]
[2]
[3]])
>([[1 2 3]
[4 5 6]])

创建递增数组

递增数组使用np.arange()方法,该方法需要传入数组的长度

1
2
3
4
import numpy as np
arr = np.arange(1,21,2)
print(arr)
>(1 3 5 7 9 11 13 15 17 19)

##创建同值数组
需要创建同值数组时,使用np.ones()np.zeros()方法,该方法需要传入数组的形状参数

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
# 创建同值数组————全1数组
arr1 = np.ones((2,3))
print(arr1)
# 创建同值数组————全0数组
arr2 = np.zeros((2,3))
print(arr2)
>([[1. 1. 1.]
[1. 1. 1.]])
>([[0. 0. 0.]
[0. 0. 0.]])

注意:为避免插入浮点数时被截断,.ones().zeros()方法默认创建的数组类型是float64,若需要创建int类型的数组,需要指定dtype参数

创建随机数组

创建随机数组,可以使用np.random.rand()方法,该方法需要传入数组的形状参数

1
2
3
4
5
import numpy as np
arr = np.random.rand(2,3)
print(arr)
>([[0.5488135 0.71518937 0.60276338]
[0.54488318 0.4236548 0.64589411]])

np.random.rand()方法创建的随机数组,元素值在[0,1)之间,若需要创建其他范围的随机数组,需要进行缩放或平移

1
2
3
4
5
6
import numpy as np
arr = (100-60)*np.random.random((3,3))+60
print(arr)
>([[86.27722064 80.22275727 77.21222227]
[82.22222222 82.22222222 82.22222222]
[82.22222222 82.22222222 82.22222222]])
1
2
3
arr = np.random.randint(10,100,(1,15)) # 形状为(1,15)的矩阵
print(arr)
>[[90 66 59 15 58 36 63 59 72 37 79 13 35 63 33]]

数组的索引

规定将一维数组称为向量,二维数组成为矩阵

访问数组元素

与Python列表一致,访问Numpy数组元素时使用中括号,索引由0开始

访问向量

1
2
3
4
5
6
7
8
import numpy as np
# 创建向量
arr1 = np.arange(1,10)
# 访问元素
print(arr1[1])
print(arr1[-1])
>(2)
>(9)

访问矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
# 创建矩阵
arr2 = np.arange(1,10).reshape((3,3))
# 访问元素
print(arr2[1,1])
print(arr2[-1,-1])
# 修改元素
arr2[1,1] = 100
print(arr2)
>([[1 2 3]
[4 100 6]
[7 8 9]])
>(5)
>(9)

花式索引

花式索引(fancy indexing),形如arr[indices],其中indices是一个数组,用于指定需要访问的元素的索引,其与矩阵访问的区别在于矩阵只能访问指定数据的行或列,而花式索引可以访问任意位置的元素

1
2
3
4
5
6
7
8
9
10
import numpy as np
# 创建矩阵
arr2 = np.arange(1,10).reshape((3,3))
# 花式索引
print(arr2)
print(arr2[[0,2],[0,2]]) # 第零行第零个元素和第二行第二个元素
>[[1 2 3]
[4 5 6]
[7 8 9]]
>([1 9])

根据以上实例,花式索引也就是用向量来替代普通索引的行列元素,且花式索引输出的仍然是一个向量

索引方式 向量 矩阵
普通索引 arr1[i] arr2[i,j]
花式索引 arr1[[indices]] arr2[[indices1,indices2]]

访问数组切片

向量的切片

向量与列表切片的操作完全一致

索引负责其指向区域的右侧一个单元格

当明确知道从第x给元素切到第y个元素时

1
2
3
4
5
6
7
8
9
10
import numpy as np
arr1 = np.arange(10)
print(arr1)
print(arr1[1:4])
print(arr1[ :4])
print(arr1[4: ])
>[0 1 2 3 4 5 6 7 8 9]
>[1 2 3]
>[0 1 2 3]
>[4 5 6 7 8 9]

当明确切除数组的开头与结尾

1
2
3
4
print(arr1[2:-2])
print(arr1[ :-2])
>[2 3 4 5 6 7]
>[0 1 2 3 4 5 6 7]

当明确隔几个元素采样一次时

1
2
print(arr1[1:8:2])
>[1 3 5 7]

矩阵的切片

矩阵的切片与向量的切片操作一致,只是需要在方括号中添加逗号,逗号前的索引表示行,逗号后的索引表示列

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
# 创建矩阵
arr2 = np.arange(1,10).reshape((3,3))
# 矩阵的切片
print(arr2)
print(arr2[1:3,1:3])
>[[1 2 3]
[4 5 6]
[7 8 9]]
>([[5 6]
[8 9]])

基于矩阵的切片功能,可以提取矩阵的部分行

1
2
3
4
5
6
7
8
9
10
11
arr3 = np.arange(1,21).reshape(4,5)
print(arr3)
print(arr3[2,:]) # 提取第二行
print(arr3[1:3,:]) # 提取1-2行
>[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]]
>[11 12 13 14 15]
>[[ 6 7 8 9 10]
[11 12 13 14 15]]

考虑代码的简介,当提取矩阵的部分行时,只需要在方括号中添加行索引即可,不需要添加逗号

1
2
print(arr3[2,:]) # 规范的提取第行
print(arr3[3]) # 简便的提取行

注意提取列的时候不能简写

提取矩阵的列

1
2
3
4
5
6
7
8
9
10
11
12
13
arr4 = np.arange(1,21).reshape(4,5)
print(arr4)
print(arr4[:,2]) # 提取第3列
print(arr4[:,1:3]) # 提取第2-3列
>[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]]
>[ 3 8 13 18]
>[[ 2 3]
[ 7 8]
[12 13]
[17 18]]

值得注意的是,当提取某一个单独的列时,出来的结果是一个向量,其实这么做只是为了省空间,我们知道,列矩阵必须用两层中括号来存储,使用向量输出可以大幅减少内存使用
若想提取真正的列矩阵,需要使用reshape方法进行升级再转置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
arr4 = np.arange(1,16).reshape(3,5)
print(arr4)
print(arr4[:,2]) # 提取第3列
print(arr4[:,1:3]) # 提取第2-3列
cut = arr4[:,2].reshape(1,3) # 提取第3列并升级为列矩阵
print(cut.T)
>[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]]
>[ 3 8 13]
>[[ 2 3]
[ 7 8]
[12 13]]
>[[ 3]
[ 8]
[13]]

与Python列表不同,NumPy数组的切片仅仅是原数组的一个视图,换言之,NumPy切牌你并不会创建新的变量,而是指向原数组的一个引用,因此,当修改切片时,原数组也会被修改

1
2
3
4
5
6
import numpy as np
arr = np.arange(10)
cut = arr[ :3]
cut[0] = 100
print(arr)
>([100 1 2 3 4 5 6 7 8 9])

深度学习中为节省内存,将多次使用arr[:]=<表达式>来替代arr=<表达式>

备份切片为新变量可以使用.copy()方法

1
2
3
4
5
6
import numpy as np
arr = np.arange(10)
cut = arr[ :3].copy()
cut[0] = 100
print(arr)
>([0 1 2 3 4 5 6 7 8 9])

数组赋值仅是绑定

与NumPy数组的切片一样,NumPy数组完整的赋值给另一个数组,也只是指向原数组的一个引用,因此,当修改数组时,原数组也会被修改

1
2
3
4
5
6
import numpy as np
arr = np.arange(10)
arr2 = arr
arr2[0] = 100
print(arr)
>([100 1 2 3 4 5 6 7 8 9])

若需复制为新数组,方法同数组的切片,使用.copy()方法

数组的变形

数组的转置方法为.T只对矩阵有效,因此遇到向量要先将其转化为矩阵

向量的转置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
arr1 = np.arange(1,4)
arr2 = arr1.reshape(1,-1) # 升级为矩阵
arr3 = arr2.T # 转化为列矩阵
print(arr1)
print(arr2)
print(arr3)
>[1 2 3]
>[[1 2 3]]
>[[1]
[2]
[3]]

# 也可以直接升级为列矩阵
arr4 = arr1.reshape(-1,1)
print(arr4)
>[[1]
[2]
[3]]

矩阵的转置

列矩阵的转置如下所示

1
2
3
4
5
6
7
8
9
import numpy as np
arr1 = np.arange(1,4).reshape(-1,1)
arr2 = arr1.T
print(arr1)
print(arr2)
>[[1]
[2]
[3]]
>[[1 2 3]]

数组的翻转

数组的翻转方法有两个,一个是上下翻转np.flipud(),表示up-down翻转,另一个是左右翻转np.fliplr(),表示left-right翻转,其中,向量只能使用np.flipud()方法。

向量的翻转

1
2
3
4
5
import numpy as np
arr1 = np.arange(10)
arr_ud = np.flipud(arr1)
print(arr_ud)
>[9 8 7 6 5 4 3 2 1 0]

矩阵的翻转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
arr1 = np.arange(1,21).reshape(4,5)
arr_lr = np.fliplr(arr1)
arr_ud = np.flipud(arr1)
print(arr1)
print(arr_lr)
print(arr_ud)
>[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]
[16 17 18 19 20]]
>[[ 5 4 3 2 1]
[10 9 8 7 6]
[15 14 13 12 11]
[20 19 18 17 16]]
>[[16 17 18 19 20]
[11 12 13 14 15]
[ 6 7 8 9 10]
[ 1 2 3 4 5]]

矩阵的重塑

矩阵的重塑方法为.reshape(),其中,-1表示自动计算维度,例如,将一个向量升级为列矩阵时,可以使用arr.reshape(-1,1),将一个向量升级为行矩阵时,可以使用arr.reshape(1,-1)

数组的拼接

向量的拼接

两个向量拼接,将得到一个新的加长版向量

1
2
3
4
5
6
import numpy as np
arr1 = np.array([1,2,3])
arr2 = np.array([4,5,6])
arr3 = np.concatenate([arr1,arr2])
print(arr3)
>[1 2 3 4 5 6]

矩阵的拼接

两个矩阵可以按照不同的维度进行拼接,但拼接式必须注意维度的吻合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
arr1 = np.array([[1,2,3],[4,5,6]])
arr2 = np.array([[7,8,9],[10,11,12]])
# 按第一维度(行)拼接
arr3 = np.concatenate([arr1,arr2]) # 默认参数axis=0
print(arr3)
# 按第二维度(列)拼接
arr4 = np.concatenate([arr1,arr2],axis=1)
print(arr4)
>[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
>[[ 1 2 3 7 8 9]
[ 4 5 6 10 11 12]]

数组的分裂

向量的分裂,将得到若干个更短的向量

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
arr = np.arange(10,100,10)
# 分裂数组
arr1,arr2,arr3 = np.split(arr,[2,8]) # 从第二和第八个元素开始分裂
print(arr)
print(arr1)
print(arr2)
print(arr3)
>[10 20 30 40 50 60 70 80 90]
>[10 20]
>[30 40 50 60 70 80]
>[90]

np.split()函数中,给出的第二个参数[2,8]表示再索引[2]和索引[8]的位置截断

矩阵的分裂

矩阵分裂同样可以以不同维度进行

1
2
3
4
5
6
7
8
9
import numpy as np
# 创建矩阵
arr = np.array(1,0).reshape(2,4)
# 按第一个维度(行)分裂
arr1,arr2 = np.split(arr,[1]) # 默认参数axis = 0
print(arr1,'\n\n',arr2)
# 按第二维度分裂
arr1,arr2,arr3 = np.split(arr,[1,3],axis = 1)
print(arr1,'\n\n',arr2,'\n\n',arr3)

数组的运算

python基础中,常用的运算符如表所示,Numpy的运算符与之相同

数组与系数的运算

以矩阵为例,向量与系数的操作与python相同

1
2
3
4
5
6
7
8
9
import numpy as np
arr = np.arange(1,9).reshanpe(2,4)
print(arr + 10)
print(arr - 10)
print(arr * 10)
print(arr / 10)
print(arr ** 10)
print(arr // 10)
print(arr % 10)

数组与数组之间的运算

同维度数组间的运算即对应元素之间的运算,这里仅以矩阵为例,向量与向量之间的操作相同

1
2
3
4
5
6
7
8
9
10
import numpy as np
arr1 = np.arange(-1,-9,-1).reshape(2,4)
arr2 = arr1
print(arr1 + arr2)
print(arr1 - arr2)
print(arr1 * arr2)
print(arr1 / arr2)
print(arr1 ** arr2)
print(arr1 // arr2)
print(arr1 % arr2)

乘法是遵循对应元素相乘的,可以称之为“逐元素乘积”,线性代数中矩阵乘法的实现用对应函数

广播

在二维数组中,不同形状的数组之间的运算有以下规则

  • 如果是向量与矩阵之间做运算,向量自动升级为行矩阵
  • 如果某矩阵是行矩阵或列矩阵,则其被广播,以适配另一个矩阵的形状

向量被广播

当一个形状为(x,y) 的矩阵与一个向量做运算时,要求该向量的形状必须为y,运算时向量会自动升级为形状为(1,y)的行矩阵,该å½¢式为(1,y)的行矩阵再自动被广播为形状(x,y)的矩阵,这样就与另一个矩阵的形状适配了

1
2
3
4
5
6
7
8
import numpy as np
# 向量
arr1 = np.array([-100,0,100])
print(arr1)
# 矩阵
arr2 = np.random.random((10,3))
print(arr2)
print(arr1 * arr2)

列矩阵被广播

当一个形状为(x,y)的矩阵与一个列矩阵做运算时,要求该列矩阵的形状必须为(x,1)的矩阵再自动被广播为形状(x,y)的矩阵,这样就与另一个矩阵的形状适配了

1
2
3
4
5
6
7
8
9
import numpy as np
# 列矩阵
arr1 = np.arange(3).reshape(3,1)
print(arr1)
# 矩阵
arr2 = np.ones((3,5))
print(arr2)
# 广播
print(arr1 * arr2)

行矩阵与列矩阵同时被广播

当一个形状为(1,y)的行矩阵与形状为(x,1)的列矩阵做运算时,这两矩阵都会被自动广播为形状(x,y)的矩阵,以互相适配

1
2
3
4
5
6
# 向量
arr1 = np.arange(3)
# 列矩阵
arr2 = np.arange(3).reshape(3,1)
# 广播
print(arr1 * arr2) # 此为向量的叉乘

数组的函数

矩阵乘积

  • 第五章中的乘法都是“逐元素相乘”,这里是线性代数中的矩阵乘积,只需要使用np.dot()函数
  • 当矩阵乘积中混有向量时,根据需求,其可充当行矩阵,也可充当列矩阵,但混有向量时输出结果必为向量

向量与向量的乘积

设两个向量的形状按前后顺序分别为(1,5)5,1,从矩阵乘法的角度,有(1,5)x(5,1)=(1,1),因此输出的应该是形状为(1,1)的向量

1
2
3
4
5
6
import numpy as np
# 创建数组
arr1 = np.arange(5)
arr2 = np.arange(5)
# 矩阵乘积
print(np.dot(arr1,arr2))

向量与矩阵的乘积

设向量的形状是(1,5),矩阵的形状是(5,3),有(1,5)x(5,3)=(1,3),因此输出的也应该是形状为(1,3)的向量

1
2
3
4
5
6
import numpy as np
# 创建数组
arr1 = np.arange(5)
arr2 = np.arange(15).reshape(5,3)
# 矩阵乘积
print(np.dot(arr1,arr2))

向量与矩阵的乘积

设向量的形状是(1,5),矩阵的形状是(5,3),有(1,5)x(5,3)=(1,3),因此输出的也应该是形状为(1,3)的向量

1
2
3
4
5
6
import numpy as np
# 创建数组
arr1 = np.arange(5)
arr2 = np.arange(15).reshape(5,3)
# 矩阵乘积
print(np.dot(arr1,arr2))

向量与矩阵的乘积

设向量的形状是(1,5),矩阵的形状是(5,3),有(1,5)x(5,3)=(1,3),因此输出的也应该是形状为(1,3)的向量

1
2
3
4
5
6
import numpy as np
# 创建数组
arr1 = np.arange(5)
arr2 = np.arange(15).reshape(5,3)
# 矩阵乘积
print(np.dot(arr1,arr2))

向量与矩阵的乘积

设向量的形状是(5,1),矩阵的形状是(3,5),有(5,1)x(3,5)=(3,1),因此输出的也应该是形状为(3,1)的向量

1
2
3
4
5
6
import numpy as np
# 创建数组
arr1 = np.arange(5)
arr2 = np.arange(15).reshape(3,5)
# 矩阵乘积
print(np.dot(arr1,arr2))

矩阵与矩阵的乘积

设两个矩阵的形状按前后顺序分别是(5,2)以及(2,8),有(5,2)x(2,8)=(5,8)

1
2
3
4
import numpy as np
arr1 = np.arange(10).reshape(5,2)
arr2 = np.arange(16).reshape(2,8)
print(np.dot(arr1,arr2))

数学函数

Numpy设计了许多数学函数,此处仅列举深度学习中常用的几个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import numpy as np
# 绝对值函数
arr_v = np.array([-10,0,10])
abs_v = np.abs(arr_v)
print("原数组是",arr_v)
print("绝对值是",abs_v)
# 三角函数
theta = np.arange(3) * np.pi/2
sin_v = np.sin(theta)
cos_v = np.cos(theta)
tan_v = np.tan(theta)
print("原数组是",theta)
print("正弦函数",sin_v)
print("余弦函数",cos_v)
print("正切函数",tan_v)
# 对数函数
x = np.array([1,10,100,1000])
print("x = ",x)
print("ln(x) = ",np.log(x))
print("log2(x) = ",np.log(x)/np.log(2))
print("log10(x) = ",np.log(x)/np.log(10))
# 指数函数
x = np.arange(1,4)
print("x = ",x)
print("e^x",np.exp(x))
print("2^x",2**x)
print("10^x",10**x)