文章目录
前言
本篇总结、介绍创建Numpy数组的几种主要方法 [1] [2]。
1. 从列表等其他Python的结构进行转换
1.1 array
numpy.array(object, dtype=None, *, copy=True, order=‘K’, subok=False, ndmin=0):将输入转换为Numpy数组 [3]
- object:类数组(array_like)。官方文档给出的类数组的定义包括数组,公开数组接口的任何对象,__array__方法返回数组的对象,或任何(嵌套)序列
- dtype:数据类型,可选参数。如果没有指定,那么数据类型将被确定为在序列中保存对象所需的最小类型
- copy:布尔值,可选参数。如果为true(默认值),则返回的数组会复制对象object(否则只是简单的引用)。需要特别注意的是,numpy.array是深拷贝 [4]。但是,当obj是__array__方法返回数组的对象,obj是嵌套序列,或者需要副本来满足任何其他要求(dtype,顺序等)时,会强行进行复制。这里涉及到Python中赋值引用、浅拷贝、深拷贝的概念 [5]
- order: {‘K’,‘A’,‘C’,‘F’},可选参数。指定阵列的内存布局。如果object不是数组,则新创建的数组将按C顺序排列(行主要),除非指定了’F’,在这种情况下,它将采用Fortran顺序(列主要)[6] [7]
- subok:布尔值,可选参数。如果为True,则子类将被传递,否则返回的数组将被强制为基类数组(默认)
- ndmin:整数值,可选参数。指定结果数组应具有的最小维数。根据需要,将根据需要预先设置形状
注释:
这里,我们需要注意类数组(array_like)和Numpy数组(ndarray)的联系和区别。类数组是一个更广泛、更具一般性的概念,Numpy的很多函数都作用在类数组上,因此不仅可以用于操作Numpy数组,而且可以用于操作Python原生的列表等类数组对象。从这一点上来看,Numpy非常方便和强大。
(1)一维数组:
x = np.array([1, 2, 3])
print(x)
print(type(x))
print(x.shape)
输出
[1 2 3]
<class 'numpy.ndarray'>
(3,)
(2)二维数组:
x = np.array([[1, 2, 3], [4, 5, 6]])
print(x)
print(type(x))
print(x.shape)
输出
[[1 2 3]
[4 5 6]]
<class 'numpy.ndarray'>
(2, 3)
(3)dtype参数:
x = np.array([1, 2, 3],dtype=complex)
print(x)
print(type(x))
print(x.shape)
输出
[1.+0.j 2.+0.j 3.+0.j]
<class 'numpy.ndarray'>
(3,)
(4)copy参数:
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array(arr1,copy=False)
print(arr1)
print(arr2)
arr1[0] = [0,1,2]
print(arr1)
print(arr2)
输出
[[1 2 3]
[4 5 6]]
[[1 2 3]
[4 5 6]]
[[0 1 2]
[4 5 6]]
[[0 1 2]
[4 5 6]]
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array(arr1,copy=True)
print(arr1)
print(arr2)
arr1[0] = [0,1,2]
print(arr1)
print(arr2)
输出
[[1 2 3]
[4 5 6]]
[[1 2 3]
[4 5 6]]
[[0 1 2]
[4 5 6]]
[[1 2 3]
[4 5 6]]
(5)subok参数:
np.array(np.mat('1 2; 3 4'))
输出
array([[1, 2],
[3, 4]])
但是,
np.array(np.mat('1 2; 3 4'), subok=True)
输出
matrix([[1, 2],
[3, 4]])
(6)ndmin参数:
x = np.array([1, 2, 3],ndmin=2)
print(x)
print(type(x))
print(x.shape)
输出
[[1 2 3]]
<class 'numpy.ndarray'>
(1, 3)
注释:
个人觉得,相比下面的numpy.asarray,numpy.array更常用也更推荐。
1.2 asarray
numpy.asarray(a, dtype=None, order=None):将输入转换为Numpy数组
- a:类数组。可以是列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组
- dtype:数据类型,可选参数。
- order:{‘K’,‘A’,‘C’,‘F’},可选参数。
注释:
numpy.asarray函数类似numpy.array函数,其都可以将类数组转化为ndarray(笔者注:虽然,numpy.asarray和numpy.array的输入参数都写的是类数组,但是具体描述有差异,详见上述两者的输入参数的解释。因此,两者的作用范围是否一致暂不清楚,目前也没有必要搞的那么清楚。)。两者的主要区别在于当输入对象为Numpy ndarray时,numpy.array默认(copy=True)为深拷贝,而numpy.asarray并不会对输入对象进行拷贝,而是进行了直接引用,除非dtype改变 [4] [8] [9]。
Numpy.array:
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array(arr1,copy=True)
print(arr1)
print(arr2)
arr1[0] = [0,1,2]
arr1[1][0] = -4
print(arr1)
print(arr2)
输出
[[1 2 3]
[4 5 6]]
[[1 2 3]
[4 5 6]]
[[ 0 1 2]
[-4 5 6]]
[[1 2 3]
[4 5 6]]
Numpy.asarray:
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.asarray(arr1)
print(arr1)
print(arr2)
arr1[0] = [0,1,2]
arr1[1][0] = -4
print(arr1)
print(arr2)
输出:
[[1 2 3]
[4 5 6]]
[[1 2 3]
[4 5 6]]
[[ 0 1 2]
[-4 5 6]]
[[ 0 1 2]
[-4 5 6]]
2. 使用Numpy内部功能函数
2.1 arange
numpy.arange([start,] stop[, step,], dtype=None):以数组形式返回给定区间内均匀间隔的值([]括起来的为可选参数)
- start:区间的起始位置(包含),可选参数,默认值为0
- stop:区间的结束位置(不包含,因此是个前闭后开的区间),必须给出的参数
- step:数值之间的间隔,可选参数,默认为1
- dtype:数据类型,可选参数。如果未指定数据类型,那么从其他输入参数推断数据类型
注释:
numpy中的arange函数和python中内建的range函数类似,区别在于arange返回的是数组(ndarray)而range返回的是列表(list)。
arange函数返回的是一维数组。arange函数经常与reshape函数一起使用,将一维数组转换为高维数组。
numpy.reshape(a, newshape, order=‘C’):在不改变数据的情况下为数组赋予新的形状
- a:待重塑的类数组
- newshape:重塑之后的数组形状(shape),用整数或者整数元组/列表等形式来表示
- order:数据在计算机内存中的存储顺序,可选参数,可选’C’, ‘F’, 'A’三者中的一个
# 一维数组
x = np.arange(8)
print(x)
print(type(x))
print(x.shape)
# 二维数组
x = np.reshape(x,(2,4)) # 整数组成的元组
print(x)
print(x.shape)
# 三维数组
x = np.reshape(x,(2,2,2)) # 整数组成的元组
print(x)
print(x.shape)
# 由高维数组降维到一维数组
x = np.reshape(x,8) # 整数
print(x)
print(x.shape)
输出
[0 1 2 3 4 5 6 7]
<class 'numpy.ndarray'>
(8,)
[[0 1 2 3]
[4 5 6 7]]
(2, 4)
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
(2, 2, 2)
[0 1 2 3 4 5 6 7]
(8,)
注释:
每个Numpy数组的实例也都有自己的reshape方法(注意与函数reshape区别),其语法如下:
a.reshape(shape, order=‘C’):在不改变数据的情况下为数组赋予新的形状(a为Numpy数组实例)
无论从语法还是功能上来说,Numpy数组的reshape方法和Numpy的reshape函数都一样。两者的主要区别在于,(1)Numpy的reshape函数可以直接对诸如python列表对象进行操作(但返回的依然是Numpy ndarray对象),而Numpy数组的reshape方法则不行。(2)Numpy数组的reshape方法支持形状(shape)参数的每个元素作为单独的参数传入,而Numpy的reshape函数不行。 看一下下面的例子。
我们先来看一下第一点。我们首先看一下Numpy的reshape函数:
list1 = [0,1,2,3,4,5,6,7,8]
x = np.reshape(list1,(3,3))
print(x)
输出
[[0 1 2]
[3 4 5]
[6 7 8]]
我们再来看一下Numpy数组的reshape方法:
list1 = [0,1,2,3,4,5,6,7,8]
list1.reshape(list1,(3,3))
print(list1)
输出
AttributeError: 'list' object has no attribute 'reshape'
报错了!
我们再来看一下第二点。我们首先看一下Numpy的reshape函数:
# 形状参数作为一个整体传入
x = np.arange(8)
np.reshape(x,(2,4))
输出
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
我们再来看一下Numpy数组的reshape方法:
# 形状参数的元素单独传入
x = np.arange(8)
np.reshape(x,2,4) # TypeError: order must be str, not int
我们再来看一下Numpy数组实例的reshape方法:
# 形状参数作为一个整体传入
x = np.arange(8)
x.reshape((2,4))
输出
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
# 形状参数的元素单独传入
x = np.arange(8)
x.reshape(2,4)
输出
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
也是可以的!
2.2 linspace
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0):以数组形式返回给定区间内指定数目的均匀间隔的值
- start:类数组,表示区间的起始值(从1.16.0版本开始,strat可以为类数组;之前,start只能为标量。下面的stop和start一样。)
- stop:类数组,表示区间的终点值(返回的数组是否包含终点值,取决于endpoint参数)
- num:整数型,可选参数。表示生成的样本数目,即返回的数组的长度
- endpoint:布尔值,可选参数。如果为True,那么生成的数组包含stop;否则,不包含stop
- retstep:布尔值,可选参数。如果为True,那么将以元组(‘数组’, ‘步长’)的形式返回生成的数组及数组元素之间的间隔
- dtype:数据类型,可选参数。如果未指定数据类型,那么从其他输入参数推断数据类型
- axis:整数型,可选参数。指定结果中用于存储样本的轴。只有当start和stop为数组时,该参数才有意义(从1.16.0版本开始才有的新的输入参数)
相比arange,linspace可以指定数组的长度。
x1 = np.linspace(2,3,num=5)
x2 = np.linspace(2,3,num=5,endpoint=False)
x3 = np.linspace(2,3,num=5,retstep=True)
x4 = np.linspace(2,3,num=5,dtype=int)
print(x1)
print(x2)
print(x3)
print(x4)
输出
[2. 2.25 2.5 2.75 3. ]
[2. 2.2 2.4 2.6 2.8]
(array([2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)
[2 2 2 2 3] # 将[2. 2.25 2.5 2.75 3. ]强制转换为整数型
在numpy 1.16.0版本之前,linspace函数和arange函数一样,返回的都是一维数组。因此,linspace函数也可以与reshape函数一起使用,创建更高维数组,在此不再赘述。
注释:
和linspace类似的还有logspace、geomspace,在此不再赘述。
2.3 zeros、zeros_like
numpy.zeros(shape, dtype=float, order=‘C’):创建元素全部为0,形状(shape)和数据类型(dtype)指定的数组
- shape:数组形状,用整数或者整数元组/列表等形式来表示,比如2,(2,3),[2,3]
- dtype:数据类型,可选参数
- order:{‘C’, ‘F’},可选参数
x1 = np.zeros(2)
x2 = np.zeros((2,))
x3 = np.zeros((2,1))
print(x1)
print(x2)
print(x3)
输出:
[0. 0.]
[0. 0.]
[[0.]
[0.]]
numpy.zeros_like(a, dtype=None, order=‘K’, subok=True, shape=None):返回与给定数组a具有相同形状和数据类型的全0数组(注意数组形状和数据类型都相同)
- a:类数组
x1 = np.ones((2,3))
x2 = np.zeros_like(x1)
x3 = np.ones((2,3),dtype=int)
x4 = np.zeros_like(x3)
print(x1)
print(x2)
print(x3)
print(x4)
输出:
[[1. 1. 1.]
[1. 1. 1.]]
[[0. 0. 0.]
[0. 0. 0.]]
[[1 1 1]
[1 1 1]]
[[0 0 0]
[0 0 0]]
注释:
需要注意的且比较有意思的一点是:zeros和zeros_like都可以传入列表、元组等类数组类型,但意义和返回的结果却大相径庭。我们看一下下面的例子。
np.zeros([2,3])
输出
array([[0., 0., 0.],
[0., 0., 0.]])
而
np.zeros_like([2,3])
输出
array([0, 0])
一言以蔽之,zeros会将传入的列表直接作为数组形状参数,而zeros_like会将传入的列表的形状作为数组的形状。
2.4 ones、ones_like
numpy.ones(shape, dtype=float, order=‘C’):创建元素全部为1,形状(shape)和数据类型(dtype)指定的数组
numpy.ones_like(a, dtype=None, order=‘K’, subok=True, shape=None):返回与给定数组a具有相同形状和数据类型的全1数组(注意数组形状和数据类型都相同)
ones、ones_like和zeros、zeros_like使用方法一致,详见2.3节。
2.5 empty、empty_like
numpy.empty(shape, dtype = float, order = ‘C’):创建一个形状(shape)和数据类型(dtype)指定,且未初始化的数组
numpy.empty_like(a, dtype=None, order=‘K’, subok=True, shape=None):返回与给定数组a具有相同形状和数据类型的全1数组(注意数组形状和数据类型都相同)
empty、empty_like和zeros、zeros_like使用方法一致,详见2.3节。
注释:
empty、empty_like返回数组的元素为随机数,因为它们没有初始化
2.6 full、full_like
numpy.full(shape, fill_value, dtype=None, order=‘C’):创建一个形状(shape)和数据类型(dtype)指定,且全部元素用“fill_value”填充的数组
- fill_value:标量或数组
x1 = np.full((2,3),3)
x2 = np.full((2,3),[1,2,3])
print(x1)
print(x2)
输出:
[[3 3 3]
[3 3 3]]
[[1 2 3]
[1 2 3]]
注释:
如果fill_value为数组,那么需要注意fill_value的形状和待创建数组的形状满足广播(Broadcast)。
看下面一个例子:
np.full((2,3),[1,2])
会报如下错误:
ValueError: could not broadcast input array from shape (2) into shape (2,3)
numpy.full_like(a, fill_value, dtype=None, order=‘K’, subok=True, shape=None):返回与给定数组a具有相同形状和数据类型,且用指定元素fill_value填充的数组
具体用法请参考2.3节ones_like及full,不再赘述。
2.7 特殊数组
2.7.1 identity
numpy.identity(n, dtype=None):创建一个二维单位数组,即单位矩阵
- n:整数型,单位矩阵的行/列数
x = np.identity(2)
print(x)
输出
[[1. 0.]
[0. 1.]]
2.7.2 eye
numpy.eye(N, M=None, k=0, dtype=float, order=‘C’):创建一个二维数组,其对角线位置为1,其余位置为0
- N:整数,表示二维数组的行数
- M:整数,表示二维数组的列数,可选参数
- k:整数,表示对角线的索引,可选参数。0表示主对角线,正数表示主对角线上方的对角线,负数表示主对角线下方的对角线
x1 = np.eye(3)
x2 = np.eye(2,3)
x3 = np.eye(3,k=1)
x4 = np.eye(3,k=-1)
x5 = np.eye(3,k=2)
输出为
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
[[1. 0. 0.]
[0. 1. 0.]]
[[0. 1. 0.]
[0. 0. 1.]
[0. 0. 0.]]
[[0. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]]
[[0. 0. 1.]
[0. 0. 0.]
[0. 0. 0.]]
2.7.3 diag
numpy.diag(v, k=0):提取主对角线或者构造一个对角数组
- v:如果v是一维数组,那么返回一个二维的主对角数组,其中主对角线元素即为v;如果v是一个二维数组,那么返回其主对角线元素
- k:整数型,可选参数,表示对角线的索引,默认为0。k>0表示主对角线以上的对角线;反之表示主对角线以下的对角线
# 当输入参数为二维数组时,np.diag返回对角线元素
x = np.arange(9).reshape((3,3))
print(x)
print(np.diag(x))
print(np.diag(x,k=1))
输出
[[0 1 2]
[3 4 5]
[6 7 8]]
[0 4 8]
[1 5]
# 当输入参数为一维数组时,np.diag返回该一维数组构造的二维对角数组
x = np.diag([1,2,3])
print(x)
输出
[[1 0 0]
[0 2 0]
[0 0 3]]
2.7.4 tri、triu、tril
numpy.tri(N, M=None, k=0, dtype=float):返回一个数组,其在给定对角线上及其下方的元素都为1,而在给定对角线上方的元素都为0,即三角矩阵
- N:整数型,数组的行数
- M:整数型,可选参数,数组的列数,默认M=N
- k:整数型,可选参数,表示对角线的索引,默认为0。k>0表示主对角线以上的对角线;反之表示主对角线以下的对角线
x1 = np.tri(3)
x2 = np.tri(3,4)
x3 = np.tri(3,4,1)
print(x1)
print(x2)
print(x3)
输出
[[1. 0. 0.]
[1. 1. 0.]
[1. 1. 1.]]
[[1. 0. 0. 0.]
[1. 1. 0. 0.]
[1. 1. 1. 0.]]
[[1. 1. 0. 0.]
[1. 1. 1. 0.]
[1. 1. 1. 1.]]
numpy.tril(m, k=0):返回一个二维数组的下三角矩阵
- m:输入的二维数组
- k
x = np.arange(9).reshape((3,3))
print(x)
print(np.tril(x))
输出
[[0 1 2]
[3 4 5]
[6 7 8]]
[[0 0 0]
[3 4 0]
[6 7 8]]
numpy.triu(m, k=0):返回一个二维数组的上三角矩阵
numpy.triu和numpy.tril的用法一模一样,在此不多赘述。
注释:
需要注意的是,第2.7节介绍的这些方法,都只能生成二维数组。
3. 使用特殊的库函数
有些库可用于生成特殊用途的数组,这些库不一而足,在此不一一列出了。可能最常见也最常用的是random库。例如:
np.random.random((2,2))
输出
array([[0.63986367, 0.60182471],
[0.94717796, 0.9034801 ]])