numpy基础(一)

  numpy基础入门第一部分,介绍了numpy中最重要的数据结构numpy.ndarray的一些基本概念和常用操作。

基本概念

多维数组

numpy中最主要的数据对象就是多维数组,多维数组的纬度称为axis。下面例子中的这个数组有两个维度,第一个维度(axis)的长度(length)为2,第二个维度的长度为3

[[1,2,3]
 [4,5,6]]

numpy的数组(array)的数据类型为ndarray, 和python本身的数组(list)是不同的,python本身的数组(list)只提供了一维的操作,并且不支持对数组进行运算,而numpy的数组提供了更多的功能。

>>> a = np.array([[1,2,3],[4,5,6]])
>>> type(a)
<class 'numpy.ndarray'>

numpy数组(ndarray)的一些重要属性如下:
以如下数组(ndarray)为例:

>>> a
array([[[ 11,  22],
        [ 44,  55],
        [ 11,  44]],

       [[ 77,  55],
        [ 44,  55],
        [477,  55]]])

ndarray.ndim

数组的维度数目

>>> a.ndim
3

ndarray.shape

数组每个维度的长度

>>> a.shape
(2, 3, 2)

ndarray.size

数组所有元素的个数

>>> a.size
12

ndarray.dtype

数组中元素的类型,类型可以是python本身的数据类型,也可以是numpy定义的数据类型,比如numpy.int32, numpy.int16, and numpy.float64等等

>>> a.dtype
dtype('int64')

ndarray.itemsize

数组中单个元素占用的字节数

>>> a.itemsize
8

ndarray.data

数组所在的内存地址,一般不会使用

>>> a.data
<memory at 0x7f67930e69a8>

数组(ndarray)的创建

创建任意的数组

将python的list或者tuple传入numpy.array()来创建,
可是使用numpy.array()dtype参数来显示地指定元素类型

# 一维
a = np.array( [1,2,3] )
# 二维
b = np.array( [ [1,2], 
                [3,4], 
                [5,6] ] )
# 三维
c = np.array([ [ [1, 2, 3], 
                 [3 ,4, 5], 
                 [5, 6, 7] ], 
                
               [ [7, 8, 9], 
                 [4, 5, 6], 
                 [3, 2, 1] ] ])


创建指定大小的数组

使用numpy.zeros()来创建一个指定大小(shape)的全零的数组,传入的参数为包含每个维度(axis)的长度(length)的tuple, 类似的还可以使用numpy.ones()numpy.empty()创建全1或者未初始化的数组。默认的数据类型(dtype)是float64,可以通过参数dtype指定。

>>> a = np.zeros( (2,3,4) )
>>> a
array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])

>>> a = np.empty( (2,3) )
>>> a
array([[2.45126520e-316, 5.72938864e-313, 6.90063282e-310],
       [6.90063282e-310, 0.00000000e+000, 3.39285907e-310]])

>>> a = np.ones( (2,3) )
>>> a
array([[1., 1., 1.],
       [1., 1., 1.]])


使用numpy.random.random()来创建一个指定形状(shape)的元素为0-1之间随机浮点数的数组

>>> np.random.random((5,5))
array([[0.92209695, 0.31994049, 0.82087437, 0.55672011, 0.38671646],
       [0.87978651, 0.16631933, 0.25305667, 0.20991795, 0.27141552],
       [0.65721032, 0.33116113, 0.72580006, 0.24957755, 0.51630277],
       [0.17331517, 0.73900267, 0.41050214, 0.75883384, 0.8719157 ],
       [0.65308589, 0.85678774, 0.77877104, 0.89501972, 0.89551946]])

创建序列数组

numpy.arange

使用numpy.arange()来创建一个一维的序列数组(ndarray),该函数和python的range()类似,产生的数组类型为ndarray而不是list, 并且支持产生浮现数序列。给numpy.arange()传入一个参数,则参数结束值;传入两个参数,参数按顺序为初始值结束值;传入三个参数为,参数按顺序为初始值结束值步长。生成的数组中包含初始值不包含结束值(对整数成立,对浮点数来说由于精度问题可能存在其他情况)。

>>> np.arange(5)
array([0, 1, 2, 3, 4])

>>> np.arange(1,5,1)
array([1, 2, 3, 4])

>>> np.arange(0.1,0.6,0.2)
array([0.1, 0.3, 0.5])


注意:
np.arange()用于生成浮点数时,由于浮点数精度问题得到的序列长度可能是不确定的,可能会多一个或者少一个

>>> a = np.arange(0.1,0.1000005,0.00000001)
>>> a.size
51                  #由于0.00000001无法精确的用二进制表示,这里多生成了一个数字
>>> a
array([0.1       , 0.10000001, 0.10000002, 0.10000003, 0.10000004,
       0.10000005, 0.10000006, 0.10000007, 0.10000008, 0.10000009,
       0.1000001 , 0.10000011, 0.10000012, 0.10000013, 0.10000014,
       0.10000015, 0.10000016, 0.10000017, 0.10000018, 0.10000019,
       0.1000002 , 0.10000021, 0.10000022, 0.10000023, 0.10000024,
       0.10000025, 0.10000026, 0.10000027, 0.10000028, 0.10000029,
       0.1000003 , 0.10000031, 0.10000032, 0.10000033, 0.10000034,
       0.10000035, 0.10000036, 0.10000037, 0.10000038, 0.10000039,
       0.1000004 , 0.10000041, 0.10000042, 0.10000043, 0.10000044,
       0.10000045, 0.10000046, 0.10000047, 0.10000048, 0.10000049,
       0.1000005 ]) #好像0.1000005也被加进去了,其实并不是
>>> b = a[50]
>>> b == 0.1000005
False
>>> b - 0.1000005
-2.636779683484747e-16 #由于0.00000001存在误差,在加了50次后得到的值略小于0.1000005


numpy.linspace

为了创建指定区间包含指定元素个数的数组,可以使用numpy.linspace(),该函数会根据指定的区间和元素个数自动决定步长。
该函数参数为起始值结束值元素个数,其中起始值结束值都会包含在生成的数组中
numpy.linspace()默认数据类型为float64

>>> a = np.linspace(0.1, 0.1000005, 50)
>>> a
array([0.1       , 0.10000001, 0.10000002, 0.10000003, 0.10000004,
       0.10000005, 0.10000006, 0.10000007, 0.10000008, 0.10000009,
       0.1000001 , 0.10000011, 0.10000012, 0.10000013, 0.10000014,
       0.10000015, 0.10000016, 0.10000017, 0.10000018, 0.10000019,
       0.1000002 , 0.10000021, 0.10000022, 0.10000023, 0.10000024, #后面的是跳过了一个数0.10000025
       0.10000026, 0.10000027, 0.10000028, 0.10000029, 0.1000003 , 
       0.10000031, 0.10000032, 0.10000033, 0.10000034, 0.10000035,
       0.10000036, 0.10000037, 0.10000038, 0.10000039, 0.1000004 ,
       0.10000041, 0.10000042, 0.10000043, 0.10000044, 0.10000045,
       0.10000046, 0.10000047, 0.10000048, 0.10000049, 0.1000005 ])

# 如果指定的类型为整数,根据要求生成的数组个数计算出的步长为小数时,linspace()会把生成数组中对应小数取整得到整数数组
>>> a = np.linspace(1, 8, 6,dtype=np.int64)
>>> a
array([1, 2, 3, 5, 6, 8])
>>> a = np.linspace(1, 8, 6)
>>> a
array([1. , 2.4, 3.8, 5.2, 6.6, 8. ])


其他方式创建数组

numpy.fromfunction

该函数基本参数为用于生成数组元素的函数数组的大小(shape),可以使用dtype指定数组元素的类型,默认类型是float64。该函数会把每个数组元素的索引值传给用于生成数组元素的函数,将该函数的返回值作为元素的值。

>>> def f(a,b):
...     return a+b
... 
>>> b = np.fromfunction(f, (3,3))
>>> b
array([[0., 1., 2.],
       [1., 2., 3.],
       [2., 3., 4.]])


基本操作

算数运算会作用到数组的每一个元素上,然后生成一个新的数组

普通算数运算

>>> a = np.array([[1,2],
                  [3,4]])
>>> b = np.array([[5,6],
                  [7,8]])
# 加法
>>> c = a+b
>>> c
array([[ 6,  8],
       [10, 12]])
# 乘法
>>> c = a * b
>>> c
array([[ 5, 12],
       [21, 32]])


矩阵乘法

(还是上例的a和b)使用@运算符或者ndarry.dot()方法

>>> c = a@b
>>> c
array([[19, 22],
       [43, 50]])
>>> c = a.dot(b)
>>> c
array([[19, 22],
       [43, 50]])


注意:不同类型(int64,int32,float64…)的数组进行运算时,会自动进行类型转换,将类型统一为表示范围更大的类型

一些有用的方法

名称 作用
ndarray.min 求数组中所有元素的最小值,或者指定某一个维度(axis)的最小值
ndarray.max 求数组中所有元素的最大值,或者指定某一个维度(axis)的最小值
ndarray.sum 求数组中所有元素的和,或者指定某一个维度(axis)的最小值
ndarray.cumsum 求数组中所有元素的累计和(a1, a1+a2, a1+a2+a3…),或者指定某一个维度(axis)的累积和
numpy.exp 计算e为底数,数组中每个数作为指数的幂
numpy.sqrt 计算数组中每个数的平方根
numpy.sin 计算数组中每个数的正弦值
numpy.cos 计算数组中每个数的余弦值

数组的访问,切分和遍历

访问单个元素

数组(ndarray)的访问使用类似a[<index1>, <index2>, <index3>]或者a[<index1>][<index2>][index3]的形式来访问, 索引值从0开始,也可以使用负数来表示倒序的索引值,负数索引从-1开始

>>> a = np.array([[1,2],[3,4]])
>>> a
array([[1, 2],
       [3, 4]])
>>> a[1,1]
4
>>> a[0,1]
2
>>> a[-1,-1]
4
>>> a[1][1]
4

切片访问

使用[<start> : <end>]来表示对范围元素的访问,即数组的切片,范围中包括<start>包括<end>。如果省略<start>或者<end>分别表示从第一个元素开始以及直到最后一个元素(包括最后一个元素)。
此外还可以使用...来表示选取除了指定部分之外的全部元素, 例如,若x是5维数组, 那么

  1. x[1,2,…]等价于x[1,2,:,:,:]
  2. x[…,3]等价于x[:,:,:,:,3]
  3. x[4,…,5,:]等价于x[4,:,:,5,:]

注意:使用了...后即使访问范围只有一个元素也会返回数组类型(ndarray)

>>> a = np.fromfunction(f,(5,5), dtype=int)
>>> a
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8]])
>>> a[...]
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8]])
>>> a[1,...,1]
array(2)
>>> a[1:3,1:3]
array([[2, 3],
       [3, 4]])
>>> a[1:3,...]
array([[1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6]])

遍历数组

假设有三维数组a,可以直接使用for遍历a,循环的次数为第一个维度(axis)的长度(length)

# 生成三维数组
>>> a = np.fromfunction(lambda x,y,z:x+y+z, (3, 3, 3), dtype=int)
>>> a
array([[[0, 1, 2],
        [1, 2, 3],
        [2, 3, 4]],

       [[1, 2, 3],
        [2, 3, 4],
        [3, 4, 5]],

       [[2, 3, 4],
        [3, 4, 5],
        [4, 5, 6]]])
>>> for i in a:
...     print(i)
... 
[[0 1 2]
 [1 2 3]
 [2 3 4]]
[[1 2 3]
 [2 3 4]
 [3 4 5]]
[[2 3 4]
 [3 4 5]
 [4 5 6]]

还可以使用for循环遍历a.flat, 这样会遍历到a中的每个元素,循环次数为a中元素的个数(size)

# 还是上个例子中的数组a
>>> for i in a.flat:
...     print(i,end=" ")
... 
0 1 2 1 2 3 2 3 4 1 2 3 2 3 4 3 4 5 2 3 4 3 4 5 4 5 6 


调整数组形状(shape)

函数 作用
ndarray.ravel 利用原数组生成对应的一维数组
ndarray.reshape 利用原数组生成指定形状(shape)的数组
ndarray.T 生成原数组的转置

以上函数不改变原数组

函数 作用
ndarray.resize 改变原数组的形状(shape)
>>> a = np.floor( np.random.random((2,3)) * 10)
>>> a
array([[5., 9., 5.],
       [1., 7., 3.]])
>>> a.ravel()
array([5., 9., 5., 1., 7., 3.])
>>> a.reshape(3,2)
array([[5., 9.],
       [5., 1.],
       [7., 3.]])
>>> a.T
array([[5., 1.],
       [9., 7.],
       [5., 3.]])
# 不改变a
>>> a
array([[5., 9., 5.],
       [1., 7., 3.]])
# 改变a
>>> a.resize(3,2)
>>> a
array([[5., 9.],
       [5., 1.],
       [7., 3.]])


注意:转置和ndarray.reshape生成同样形状的数组时生成规则是不一样的,转置会把第二个维度作为第一个维度,把第一个维度作为第二个维度,而利用reshape生成同样形状的数组时并不做维度交换,具体的区别请看上述例子。

数组的合并

numpy.vstack & numpy.row_stack

这两个函数的作用是一样的,将数组在第一个维度上合并。

说明:官方文档中并没有numpy.row_stack文档,只有numpy.ma.row_stack,不过numpy.row_stack确实是可以调用的,在python中输入help(numpy.row_stack)会跳转到numpy.vstack的说明文档,因此numpy.row_stack可能只是numpy.vstack的一个别名。

关于numpy.ma是什么,参见numpy.ma

>>> a
array([[0., 1., 2.],
       [1., 2., 3.]])
>>> b
array([[0., 1., 2.],
       [2., 3., 4.]])
>>> np.vstack( (a,b) )
array([[0., 1., 2.],
       [1., 2., 3.],
       [0., 1., 2.],
       [2., 3., 4.]])
>>> np.row_stack( (a,b) )
array([[0., 1., 2.],
       [1., 2., 3.],
       [0., 1., 2.],
       [2., 3., 4.]])

numpy.hstack

将数组在第二个维度合并

# 使用上个例子中的a和b
>>> np.hstack((a,b))
array([[0., 1., 2., 0., 1., 2.],
       [1., 2., 3., 2., 3., 4.]])
>>> 

注意:如果数组没有第二个维度(一维数组),则合并第一个维度

>>> a
array([1, 2])
>>> b
array([3, 4])
>>> np.hstack((a,b))
array([1, 2, 3, 4])

numpy.column_stack

将数组在第二个维度上合并(该方法一般用来将一维数组作为列合并成二维数组,见注意部分)

详细函数说明请参考numpy.column_stack

>>> a
array([[0., 1.],
       [1., 2.]])
>>> b
array([[3., 4.],
       [4., 5.]])
>>> np.column_stack((a,b))
array([[0., 1., 3., 4.],
       [1., 2., 4., 5.]])


注意:如果数组没有第二个维度(一维数组),则将原数组转置为2维列向量然后合并

>>> a
array([1, 2])
>>> b
array([3, 4])
>>> np.column_stack((a,b))
array([[1, 3],
       [2, 4]])

numpy.column_stacknumpy.hstack只有在处理一维数组上存在上述差异,其他维度是相同的,下面是3维数组的一个测试

>>> bb = np.fromfunction(lambda x,y,z:50+x+y+z,(2,2,2))
>>> aa = np.fromfunction(lambda x,y,z:1+x+y+z,(2,2,2))
>>> aa
array([[[1., 2.],
        [2., 3.]],

       [[2., 3.],
        [3., 4.]]])
>>> bb
array([[[50., 51.],
        [51., 52.]],

       [[51., 52.],
        [52., 53.]]])
>>> np.hstack((aa,bb))
array([[[ 1.,  2.],
        [ 2.,  3.],
        [50., 51.],
        [51., 52.]],

       [[ 2.,  3.],
        [ 3.,  4.],
        [51., 52.],
        [52., 53.]]])
>>> np.column_stack((aa,bb))
array([[[ 1.,  2.],
        [ 2.,  3.],
        [50., 51.],
        [51., 52.]],

       [[ 2.,  3.],
        [ 3.,  4.],
        [51., 52.],
        [52., 53.]]])


numpy.concatenate

该函数将数组在参数axis指定的维度上合并

详细函数说明请参考numpy.concatenate

>>> aa
array([[[1., 2.],
        [2., 3.]],

       [[2., 3.],
        [3., 4.]]])
>>> bb
array([[[50., 51.],
        [51., 52.]],

       [[51., 52.],
        [52., 53.]]])
>>> np.concatenate((aa,bb), axis=2)
array([[[ 1.,  2., 50., 51.],
        [ 2.,  3., 51., 52.]],

       [[ 2.,  3., 51., 52.],
        [ 3.,  4., 52., 53.]]])
>>> np.concatenate((aa,bb), axis=1)
array([[[ 1.,  2.],
        [ 2.,  3.],
        [50., 51.],
        [51., 52.]],

       [[ 2.,  3.],
        [ 3.,  4.],
        [51., 52.],
        [52., 53.]]])
>>> np.concatenate((aa,bb), axis=0)
array([[[ 1.,  2.],
        [ 2.,  3.]],

       [[ 2.,  3.],
        [ 3.,  4.]],

       [[50., 51.],
        [51., 52.]],

       [[51., 52.],
        [52., 53.]]])


参考资料

numpy tutorial

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章