使用数组进行文件输入和输出
NumPy可以在硬盘中将数据以文本或二进制文件的形式进行存入硬盘或由硬盘载入。
np.save和np.load是高效存取硬盘数据的两大工具函数。数组在默认情况下是以未压缩的格式进行存储的,后缀名是.npy:
In [122]: arr = np.arange(10)In [123]: np.save('some_array',arr)
如果文件存放路径中没写.npy时,后缀名会被自动加上。硬盘上的数组可以使用np.load进行载入:
In [124]: np.load('some_array.npy')
Out[124]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
你还可以使用np.savez并将数组作为参数传递给该函数,用于在未压缩文件中保存多个数组,并且在载入一个.npy文件的时候,你会获得一个字典型的对象,并通过该对象很方便地载入单个数组:
In [126]: np.savez('array',a=arr,b=arr)In [127]: arch = np.load('array.npz')In [128]: arch['a']
Out[128]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
如果你的数据已经压缩好了,你可能会想要使用numpy.savez_compressed将数据存入已经压缩的文件:
np.savez_compressed('array_compressed',a=arr,b=arr)
线性代数
线性代数,比如矩阵乘法、分解、行列式等方阵数学,是所有数组类库的重要组成部分。和Matlab等其他语言相比,NumPy的线性代数中所不同的是*是矩阵的逐元素乘积,而不是矩阵的点乘积.
In [130]: a = np.arange(6).reshape(2,3)In [131]: a.T
Out[131]:
array([[0, 3],[1, 4],[2, 5]])In [132]: a.dot(a.T)
Out[132]:
array([[ 5, 14],[14, 50]])
a.dot(y)等价于np.dot(a, a.T):
In [133]: np.dot(a,a.T)
Out[133]:
array([[ 5, 14],[14, 50]])
特殊符号@也作为中缀操作符,用于点乘矩阵操作:
In [134]: a@a.T
Out[134]:
array([[ 5, 14],[14, 50]])
numpy.linalg拥有一个矩阵分解的标准函数集,以及其他常用函数,例如求逆和行列式求解:
In [135]: from numpy.linalg import inv,qrIn [136]: X = np.random.randn(5,5)In [137]: mat = X.T.dot(X)In [138]: inv(mat)
Out[138]:
array([[ 9.3067492 , 3.44854363, 4.17202619, 13.58984599, 0.90081391],[ 3.44854363, 1.44927182, 1.54939926, 4.93141315, 0.23863412],[ 4.17202619, 1.54939926, 2.08179238, 6.06650012, 0.38660456],[13.58984599, 4.93141315, 6.06650012, 20.87441372, 1.42189132],[ 0.90081391, 0.23863412, 0.38660456, 1.42189132, 0.44630741]])In [139]: mat.dot(inv(mat))
Out[139]:
array([[ 1.00000000e+00, 3.32949197e-16, 1.64815059e-16,-7.53088361e-15, 6.30895206e-16],[-1.61352798e-15, 1.00000000e+00, -7.46202572e-16,6.55728240e-15, -4.78719380e-16],[-2.70937042e-15, -7.11231664e-16, 1.00000000e+00,6.00287861e-15, -2.41241770e-16],[-3.18403374e-15, 5.08117251e-16, 2.07727866e-16,1.00000000e+00, -2.38722434e-16],[ 5.71097933e-16, 3.94927081e-16, 4.20154194e-16,3.09053489e-15, 1.00000000e+00]])In [140]: q,r = qr(mat)In [141]: r
Out[141]:
array([[-7.00190539, 6.75040451, 3.40710232, 1.85422572, 1.92828278],[ 0. , -4.65811698, 2.78909461, 0.41797978, -1.70677991],[ 0. , 0. , -2.96084437, 0.93058062, -0.68695004],[ 0. , 0. , 0. , -0.18905376, 2.68971634],[ 0. , 0. , 0. , 0. , 0.55565501]])
表达式X.T.dot(X)计算的是X和它的转置矩阵X.T的点乘积。
- 常用numpy.linalg函数
函数 | 描述 |
---|---|
diag | 将一个方阵的对角(或非对角)元素作为一维数组返回,或者将一维数组转换成一个方阵,并且在非对角线上有零点 |
dot | 矩阵点乘 |
trace | 计算对角元素和 |
det | 计算矩阵的行列式 |
eig | 计算方阵的特征值和特征向量 |
inv | 计算方阵的逆方阵 |
pinv | 计算矩阵的Moore-Penrose伪逆 |
qr | 计算QR分解 |
svd | 计算奇异值分解(SVD) |
solve | 求解x的线性系统Ax=b,其中A是方阵 |
lstsq | 计算Ax=b的最小二乘值 |
伪随机数生成
numpy.random模块填补了Python内建的random模块的不足,可以高效地生成多种概率分布下的完整样本值数组。例如,你可以使用normal来获得一个4×4的正态分布样本数组:
In [142]: samples = np.random.normal(size=(4,4))In [143]: samples
Out[143]:
array([[-1.21035431, 1.44097644, 1.28213326, 1.86843877],[ 0.41575756, -1.18904899, 0.90445916, -0.29414209],[-1.65952097, 0.45124761, -0.80380502, 0.74126157],[-1.11698142, 0.37450006, 1.71495999, 0.8454006 ]])
然而Python内建的random模块一次只能生成一个值。你可以从下面的示例中看到,numpy.random在生成大型样本时比纯Python的方式快了一个数量级:
In [144]: from random import normalvariateIn [145]: N = 1000000In [146]: %timeit samples = [normalvariate(0,1) for _ in range(N)]
1.03 s ± 1.26 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)In [147]: %timeit np.random.normal(size=N)
39.5 ms ± 27.1 ?s per loop (mean ± std. dev. of 7 runs, 10 loops each)
我们可以称这些为伪随机数,因为它们是由具有确定性行为的算法根据随机数生成器中的随机数种子生成的。你可以通过np.random.seed更改NumPy的随机数种子:
In [148]: np.random.seed(1234)
numpy.random中的数据生成函数公用了一个全局的随机数种子。为了避免全局状态,你可以使用numpy.random.RandomState生成一个随机数生成器,使数据独立于其他的随机数状态:
In [149]: rng = np.random.RandomState(1234)In [150]: rng.randn(10)
Out[150]:
array([ 0.47143516, -1.19097569, 1.43270697, -0.3126519 , -0.72058873,0.88716294, 0.85958841, -0.6365235 , 0.01569637, -2.24268495])
- numpy.random中的部分函数列表
函数 | 描述 |
---|---|
seed | 向随机数生成器传递随机状态种子 |
permulatation | 返回一个序列的随机排序,或者返回一个乱序的整数范围序列 |
shuffle | 随机排列一个序列 |
rand | 从均匀分布中抽取样本 |
randint | 根据给定的由低到高的范围抽取随机整数 |
randn | 从均值0方差1的正态分布中抽取样本(MATLAB型接口) |
binomial | 从二项分布中抽取样本 |
normal | 从正态(高斯)分布中抽取样本 |
beta | 从beta分布中抽取样本 |
chisquare | 从卡方分布中抽取样本 |