NumPy是目前python数值计算中最为重要的基础包,它的核心特征之一就是N-维数组对象——ndarray,这篇博文主要来介绍这个多维同类数据容器。
生成ndarray
ndarray包含的每种元素均为同种类型。生成数组的函数有很多,这里我介绍几种常用的。
#先导入NumPy
import NumPy as np
- np.array()参数是序列型对象,自动推断输入数据的数据类型,在创建的时候可以指定维度ndmin和数值类型dtype。
np.array("love")
output:
array('love', dtype='<U4')
- np.zeros()参数是关于d0,d1,d2,dn的元组,返回全0数组
np.zeros((2,3,4))
output:
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.]]])
- np.ones()参数是关于d0,d1,d2,dn的元组,返回全1数组
np.ones((2,3,4))
output:
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]],
[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
- np.empty()参数是关于d0,d1,d2,dn的元组,返回没有初始化数值的空数组
np.empty((2,1,3))
output:
array([[[0., 0., 0.]],
[[0., 0., 0.]]])
- np.arange()内建函数range的数组版。参数为起始值,终止值(取不到),步长
np.arange(2,15,3)
output:
array([ 2, 5, 8, 11, 14])
- np.linspace()。参数为起点值,终止值(取到),元素个数。
np.linspace(10,20,5)
np.linspace(0,1,10,endpoint=False)
output:
array([10. , 12.5, 15. , 17.5, 20. ])
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
- np.logspace()。与上面的np.linspace()相似
np.logspace(0,2,20)
output:
array([ 1. , 1.27427499, 1.62377674, 2.06913808,
2.6366509 , 3.35981829, 4.2813324 , 5.45559478,
6.95192796, 8.8586679 , 11.28837892, 14.38449888,
18.32980711, 23.35721469, 29.76351442, 37.92690191,
48.32930239, 61.58482111, 78.47599704, 100. ])
8.np.eye()返回对角线为1,其余为0的二维数组,第一个参数为numbers of rows,第二个参数为numbers of columns,默认等于第一个参数的值。
np.eye(5)
output:
array([[1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0.],
[0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
接下来介绍几个ndarray的属性
#生成随机数组,(0,1)标准正态分布随机数
data = np.random.randn(2,3)
data
#数组每一维度的数量
data.shape
#数组类型
data.dtype
#数组维数
data.ndim
output:
array([[ 0.71552267, 1.12464515, 0.84971133],
[-0.43746949, 1.12846303, -0.29032458]])
(2, 3)
dtype('float64')
2
我们可以使用astype方法来转换数组的数据类型,值得注意的是,该方法总是会生成一个新的数组。
data.astype(np.int32)
data
output:
array([[0, 1, 0],
[0, 1, 0]])
array([[ 0.71552267, 1.12464515, 0.84971133],
[-0.43746949, 1.12846303, -0.29032458]])
Numpy数组算术
任何在两个等尺寸数组之间的算术操作都应用了逐元素操作的方式:
arr = np.array([[1,2,3],[4,5,6]])
arr * arr
arr - arr
1/arr
arr * 0.5
#同尺寸数组之间的比较,会产生一个布尔值数组
arr2 = np.array([[2,4,6],[1,2,3]])
arr2 > arr
out:
array([[ 1, 4, 9],
[16, 25, 36]])
array([[0, 0, 0],
[0, 0, 0]])
array([[1. , 0.5 , 0.33333333],
[0.25 , 0.2 , 0.16666667]])
array([[0.5, 1. , 1.5],
[2. , 2.5, 3. ]])
array([[ True, True, True],
[False, False, False]])
索引与切片
- 一维数组的索引与切片,与python列表的用法有点相似
#生成一维数组
arr = np.arange(10)
arr
Out:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
#与列表不同,通过下标范围获取的新的数组是原始数组的一个视图,与原始数组共享一块数据空间,对于视图的修改会体现到原数组上
arr[5:8]=12
arr
Out:
array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
#改变aar1时,原数组也会进行改变
arr1 = arr[5:8]
arr1
arr1[:] = 24
arr
Out:
array([12, 12, 12])
array([ 0, 1, 2, 3, 4, 24, 24, 24, 8, 9])
#数组切片的拷贝可以利用.copy()
arr11 = arr[5:8].copy()
arr11
arr11[:] = 48#改变aar11时,原数组不会进行改变
arr
Out:
array([24, 24, 24])
array([ 0, 1, 2, 3, 4, 24, 24, 24, 8, 9])
- 二维数组的索引,二维数组每个索引值对应的元素是一个一维数组
#生成一个二维数组
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
#索引第三行
arr2d[2]
#索引第三行,第一列
arr2d[2][0]
#索引第三行,第一列
arr2d[2,0]
#索引第三行和第一行
arr2d[[2,0]]
Out:
array([7, 8, 9])
7
7
array([[7, 8, 9],
[1, 2, 3]])
- 二维数组的切片
#生成二维数组
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
#选择前两行
arr2d[:2]
#选择前两行的第二列和第三列
arr2d[:2,1:]
Out:
array([[1, 2, 3],
[4, 5, 6]])
array([[2, 3],
[5, 6]])
对切片表达式赋值时,整个切片都会重新赋值
arr2d[:2,1:] = 0
arr2d
Out:
array([[1, 0, 0],
[4, 0, 0],
[7, 8, 9]])
- 三维数组的索引
#三维数组的索引,2*2*3的数组
arr3d = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
arr3d[0]
arr3d[0,0]
arr3d[0][0]
Out:
array([[1, 2, 3],
[4, 5, 6]])
array([1, 2, 3])
array([1, 2, 3])
- 布尔索引
#生成一维数组names
names = np.array(["aa","bb","aa","dd","ee","aa","gg"])
#利用randn函数生成随机正态分布的二维数据data
data = np.random.randn(7,4)
names
data
names == "aa"
#利用布尔值进行索引
data[names == "aa"]
Out:
array(['aa', 'bb', 'aa', 'dd', 'ee', 'aa', 'gg'], dtype='<U2')
array([[ 0.7416918 , 0.88800978, 0.68197079, -0.53014663],
[-0.18299815, -0.48641017, 0.90295139, 2.4727419 ],
[-0.52766455, -0.36830999, 0.45128251, 0.48811192],
[ 0.71607019, 1.63065359, -0.71081597, -2.88685402],
[ 0.59853369, 0.03907715, -0.21053569, 0.18792567],
[-0.1643565 , 0.97845669, -0.92076973, -1.29995933],
[ 0.68262773, 0.61233984, -1.23746087, -0.50847237]])
array([ True, False, True, False, False, True, False])
array([[ 0.7416918 , 0.88800978, 0.68197079, -0.53014663],
[-0.52766455, -0.36830999, 0.45128251, 0.48811192],
[-0.1643565 , 0.97845669, -0.92076973, -1.29995933]])
#可以使用!=或在条件表达式前使用~对条件取反
data[names != "aa"]
data[~(names == "aa")]
cond = names == "aa"
data[~cond]
Out:
array([[-0.18299815, -0.48641017, 0.90295139, 2.4727419 ],
[ 0.71607019, 1.63065359, -0.71081597, -2.88685402],
[ 0.59853369, 0.03907715, -0.21053569, 0.18792567],
[ 0.68262773, 0.61233984, -1.23746087, -0.50847237]])
array([[-0.18299815, -0.48641017, 0.90295139, 2.4727419 ],
[ 0.71607019, 1.63065359, -0.71081597, -2.88685402],
[ 0.59853369, 0.03907715, -0.21053569, 0.18792567],
[ 0.68262773, 0.61233984, -1.23746087, -0.50847237]])
array([[-0.18299815, -0.48641017, 0.90295139, 2.4727419 ],
[ 0.71607019, 1.63065359, -0.71081597, -2.88685402],
[ 0.59853369, 0.03907715, -0.21053569, 0.18792567],
[ 0.68262773, 0.61233984, -1.23746087, -0.50847237]])
#可以对多个布尔条件进行联合,使用数学操作符|和&
mask = (names == "aa")|(names == "bb")
mask
data[mask]
#使用布尔值选择数据时,总是生成数据的拷贝
Out:
array([ True, True, True, False, False, True, False])
array([[ 0.7416918 , 0.88800978, 0.68197079, -0.53014663],
[-0.18299815, -0.48641017, 0.90295139, 2.4727419 ],
[-0.52766455, -0.36830999, 0.45128251, 0.48811192],
[-0.1643565 , 0.97845669, -0.92076973, -1.29995933]])
数组转置
#数组转置和换轴
arr = np.arange(15).reshape((3,5))
arr
arr.T
Out:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
arr = np.random.randn(6,3)
arr
np.dot(arr.T,arr)#用来计算矩阵内积
Out:
array([[ 0.58847723, 0.84348489, 1.42054432],
[ 0.95521876, -1.13381903, -0.60993457],
[-0.19601102, 0.40465638, -1.04277897],
[-0.03255321, 0.40138796, 0.27147854],
[-0.55308299, -0.57412833, -0.8741011 ],
[ 0.51149413, -0.12046626, 0.41461565]])
array([[ 1.86575541, -0.42313431, 1.14441965],
[-0.42313431, 2.66600688, 2.02866315],
[ 1.14441965, 2.02866315, 4.48701381]])
transpose方法和swapaxes方法都没有对数组进行复制,返回的是数据的视图,原数组不变
#transpose方法可以接收包含轴编号的元组,用于置换轴,使用该方法后,原数组不变
arr = np.arange(16).reshape((2,2,4))
arr
arr.transpose((1,0,2))
arr
Out:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
#swapaxes方法接收一对轴编号作为参数,并对轴进行调整用于重组数组
arr
arr.swapaxes(1,2)
arr
Out:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
array([[[ 0, 4],
[ 1, 5],
[ 2, 6],
[ 3, 7]],
[[ 8, 12],
[ 9, 13],
[10, 14],
[11, 15]]])
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
关于ndarray多维数组对象还有很多其他有意思的知识点,大家可以找一些相关书籍和教程继续学习。