目录
NumPy简介
Numpy是Numerical Python的简称,它是Python数值计算中最重要的基础包。大多数的计算包都提供基于NumPython的科学函数功能,把NumPy的数组对象作为数据交换的通用语。
NumPy主要包括:
1.nd.array这一种高效的数组结构,提供了多种基于数组的便捷操作。
2.能够对所有的数据进行快速的矩阵计算而无需使用python的循环结构。
3.对硬盘的数组数据进行读写的工具,并对内存映射文件进行操作。
4.线性代数、随机数生成以及傅里叶变换功能。
5.用于链接NumPy到C,C++等语言的API。
受限于作者本身初学Python的水平,本文仅对部分简单功能提供有限的介绍。
为什么使用NumPy
1.NumPy对于大量含有数组的数据非常有效。
2.NumPy将数据存储在连续的内存块上,这一点与其他Python内建数据结构存在不同。NumPy的库是用C语言编写的的,导致其在对内存进行操作时,不需要任何其他类型的检查和操作。且NumPy的内存量也显著小于其他Python的内建序列。
3.NumPy可以针对数组中所有元素进行操作,而不必使用Python的循环。
NumPy导入
一般为了方便,可以直接将numpy缩写为np
import numpy as np
不过不建议为了方便而写成
import numpy as*
NumPy库中的min和max等函数会和Python内建函数重名导致一些奇奇怪怪的玄学错误()
多维数组对象
NumPy的核心之一就是其使用的多维数组。ndarray是一种快速。灵活的大型数据容器。数组允许你使用类似于标量的操作方法对整个数组进行操作。
创建数组
1.使用np.array()通过list,tuple创建数组,数组的类型是自适应的,可以是整型,浮点型,字符类型等。
import numpy as np
my_list = ('a', 'b', 4, 5, 1, 4)
my_tuple = [1, 1, 4, 5, 1, 4]
arr1 = np.array(my_list)
arr2 = np.array(my_tuple)
print(arr1, arr2)
你也可以使用NumPy内置的dtype()函数查看数组类型。数据类型见后文表。
import numpy as np
my_list = ('a', 'b', 4, 5, 1, 4)
my_tuple = [1, 1, 4, 5, 1, 4]
arr1 = np.array(my_list)
arr2 = np.array(my_tuple)
print(arr1, arr1.dtype)
print(arr2, arr2.dtype)
2.使用np.arange()函数。跟Python内置的range()类似,返回一个数组。
import numpy as np
arr1 = np.arange(10)
3.使用ones根据给定形状和数据类型生成全1数组。
import numpy as np
arr1 = np.ones((2, 5), dtype=int)
print(arr1)
结果
[[1 1 1 1 1]
[1 1 1 1 1]]
4.使用ones_like根据给定数组形状生成形状一样的全1数组
5.zeros和zeros_like同上
6.eye和identity生成N*N的特征矩阵(对角线全1,其余全0)
数据类型相关
类型 | 类型代码 | 描述 |
int8,uint8 | i1,u1 | 有符号和无符号的8数位整数 |
int16,uint16 | i2,u2 | 有符号和无符号的16数位整数 |
int32,uint32 | i3,u3 | 有符号和无符号的32数位整数 |
int64,uint64 | i4,u4 | 有符号和无符号的64数位整数 |
float16 | f2 | 半精度浮点数 |
float32 | f4或f | 标准单精度浮点数,兼容C中的float |
float64 | f8或d | 标准双精度浮点数,兼容C中的double 和Python的float |
float128 | f16或g | 拓展精度浮点数 |
complex64, complex128, complex256 | c8, c16, c32 | 基于32位,62位,128位浮点数的复数 |
bool | ? | 布尔值 |
object | O | Python中object类型 |
string_ | S | 修正ASCII字符串,若长度为10则显示S10 |
unicode | U | 修正的Unicode类型,自适应同上 |
不过初学者不太需要记下来所有的数据类型,只需要记个大类,比方说整型,浮点型之类的就行了。
同时我们也可以使用astype()来转换类型。可以实现浮点型转整型(取整)等操作。
数组计算
正如前文所提到的,NumPy的数组能够不适用Python自带的循环来高效地完成一些操作。
1.带有标量运算符的,会依次直接对数组中每个元素进行对应操作。
import numpy as np
arr1 = np.random.randn(3,3)
print(arr1)
print(arr1 * arr1)
Result:
[[-0.34490866 0.36335069 -0.10776345]
[ 0.73932359 -0.19513653 -1.99190005]
[ 0.29322667 -1.67169455 -1.20543999]]
[[0.11896199 0.13202372 0.01161296]
[0.54659937 0.03807826 3.96766581]
[0.08598188 2.79456266 1.45308557]]
2.同尺寸数组比较会生成一个Bool类型的数组:
import numpy as np
arr1 = np.random.randn(3, 3)
arr2 = np.random.randn(3, 3)
print(arr1)
print(arr2)
print(arr1 < arr2)
Result:
[[-0.45428689 0.93334533 0.18404037]
[-0.17437688 -0.26061704 0.1966711 ]
[-1.39343901 -2.49725443 0.50359154]]
[[-0.66241117 -0.85100317 -1.17889197]
[ 0.25277085 -0.13349157 0.02509756]
[ 1.81059306 -1.05317884 0.79989116]]
[[False False False]
[ True True False]
[ True True True]]
数组索引与切片
基本
1.一维数组与列表类似。但不同的是,你可以将一个值赋给整个切片而不必保证数值数与切片长相等,且可以直接该表数组的值。
import numpy as np
arr1 = np.random.randn(10)
print(arr1)
arr1[2:5] = 3
print(arr1)
Result:
[-0.68037655 -0.78352394 -0.13417041 -1.18703939 2.01968328 2.42817544
-0.84770377 -0.01758374 0.64766328 0.3063849 ]
[-0.68037655 -0.78352394 3. 3. 3. 2.42817544
-0.84770377 -0.01758374 0.64766328 0.3063849 ]
如果只是想获得一份数组的拷贝,可以使用
arr2 = arr1[2:5].copy
2.高维数组。以二维数组为例,显然其每个索引值对应的是一个一维数组。
import numpy as np
arr1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr1[1])
Result:
[4 5 6]
可以通过二维坐标的形式获取某个特定元素。
arr1[0][2]
arr1[0 , 2]
可以根据喜好选择以上两种方式。
高维数组不写后续索引值可以直接引用最高维度的数组的某个低一维数组。
很好理解就不放代码了(逃)
3.切片索引。对一维数组来说之前介绍过,一样的就不再赘述。
对高维数组来说,也可以通过类似的方式,如
import numpy as np
arr1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr1[1:2, 0:1])
Result:
[[4]]
布尔索引
通过布尔类型的数组,可以根据对应的维度来筛选出True的数组。
注意,二维数组的第一维是列,第二列是行。我觉得这个有点反直觉,先提醒着()
举个例子:
import numpy as np
arr1 = np.random.randn(3, 3)
flag = np.random.randn(3)
print(arr1)
print()
print(flag)
print()
print(arr1[flag <= 0])
Result:
[[ 1.82996078 1.01518665 0.5559653 ]
[ 1.11087065 -0.69859103 0.22737699]
[-0.69159964 0.53079123 0.22767295]]
[ 0.33866842 -0.81598842 -0.20891487]
[[ 1.11087065 -0.69859103 0.22737699]
[-0.69159964 0.53079123 0.22767295]]
当布尔数组的长度不正确时,布尔值的选择数据的方法并不会报错!所以。。。自求多福!
如果有多个条件,记得使用&来代替and,|来代替or。毕竟数组跟Python自带的一些东西还是有区别的。
转置和换轴
1.转置
学过线性代数的都知道,表示X的转置。在NumPy里边也是一样,你可以把二维数组当成一个矩阵。arr1.T可以获取arr1的转置。
计算内积的时候你可以使用np.dot()实现两个矩阵的内积。如:
import numpy as np
arr1 = np.arange(12).reshape((3, 4))
arr2 = np.arange(5, 17).reshape((4, 3))
print(np.dot(arr1, arr2))
Result:
[[ 5 6 7]
[ 8 9 10]
[11 12 13]
[14 15 16]]
[[ 72 78 84]
[224 246 268]
[376 414 452]]
2.换轴
对于二维数组,转置就是换轴。但对于更高维度的数组,可以使用transpose()进行换轴。
import numpy as np
arr1 = np.arange(27).reshape((3, 3, 3))
print(arr1)
arr2 = arr1.transpose((2, 0, 1))
print(arr2)
Result:
[[[ 0 1 2] [[[ 0 3 6]
[ 3 4 5] [ 9 12 15]
[ 6 7 8]] [18 21 24]]
[[ 9 10 11] [[ 1 4 7]
[12 13 14] [10 13 16]
[15 16 17]] [19 22 25]]
[[18 19 20] [[ 2 5 8]
[21 22 23] [11 14 17]
[24 25 26]]] [20 23 26]]]
不会画图,凑活着想想吧(悲)可以看出,原本的xyz轴按照传入参数顺序变成了zxy轴
通用函数
通用函数是一类快速的逐元素计算的函数总称。其返回的是经过逐元素计算后的新数组。如:
import numpy as np
arr1 = np.arange(16).reshape((4,4))
print(np.sqrt(arr1))
Result:
[[0. 1. 1.41421356 1.73205081]
[2. 2.23606798 2.44948974 2.64575131]
[2.82842712 3. 3.16227766 3.31662479]
[3.46410162 3.60555128 3.74165739 3.87298335]]
函数名 | 描述 |
---|---|
abs、fabs | 逐元素计算整数、浮点数、复数的绝对值 |
sqrt | 计算每个元素平方根(通arr ** 0.5) |
exp | 计算每个元素的自然指数 |
log,log10,log2,log1p | 自然对数,10为底对数,2为底对数,log(1+x) |
sign | 计算符号值,1(正数),0(0),-1(负数) |
ceil | 向上取整 |
floor | 向下取整 |
rint | 保留整数,保持dtype |
modf | 分别返回整数部分和小数部分的数组 |
isnan | 返回数组中每个值是否为NaN |
isfinitge、isinf | 是否有限 |
面向数组
数组也可作为对象从而进行操作。
如np.meshgrid()函数可接受两个一维数组并生成网格(类似坐标系),并能够以此为基础进行作图(利用matplotlib,但我不会)
条件逻辑作为数组操作
np.where()是三元表达式x if condition else y的向量化。对应关系为np.where(condition,x,y).如:
import numpy as np
arr1 = np.arange(5)
arr2 = np.arange(3, 8)
res = np.where(arr1 < arr2, arr1, arr2)
print(res)
Result:
[0 1 2 3 4]
数学和统计方法/函数
sum,mean(均值),std(标准差)都是NumPy内置的函数/方法。如:
import numpy as np
arr1 = np.random.randn(4, 5)
print(arr1.mean())
print(np.mean(arr1))
这两种写法是等价的。如果出现报错,如:
<built-in method mean of numpy.ndarray object at 0x00000168845980F0>
那么请检查你的arr1.mean()是不是写成了arr1.mean
方法 | 描述 |
---|---|
sum | 沿轴方向累加 |
mean | 数学平均,0长度数组均值为NaN |
std、var | 标准差与方差,可选择自由度调整(添加参数ddof=1)即可计算样本标准差/方差 |
min、max | 你懂的 |
argmin、argmax | 第一个最小值和最大值的位置 |
cumsum | 从0开始元素累积和 |
cumprod | 从1开始元素累积积 |
axis参数
这些方法/函数都可以传入一个axis参数,默认为0,如果为1则计算给定轴向的统计值,形成一个n-1维数组。如,对于二维数组arr:
arr.mean(axis = 1)
表示计算每一列的均值,
arr.mean(axis = 0)
则计算整体均值。
而针对于argmin与argmax,axis传入1则代表第一个最小/最大值出现的n维坐标而非数字索引。
对于cumsum与cumprod,axis传入0则返回一个一维数组,长度为元素个数arr为数组,下标为数字索引,a为返回的数组
如:
import numpy as np
arr1 = np.arange(16).reshape(4,4)
print(arr1.cumsum())
Result
[ 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120]
加了axis = 1后,转为按列处理,即把每个列视为一个向量元素,适用于上文提到的公式
如:
import numpy as np
arr1 = np.arange(16).reshape(4, 4)
print(arr1)
print(arr1.cumsum(axis=1))
Result:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
[[ 0 1 3 6]
[ 4 9 15 22]
[ 8 17 27 38]
[12 25 39 54]]
排序
跟Python内置的列表差不多,Numpy的数组也能使用sort()方法进行排序。
与其他数学统计的方法类似,你也可以传入axis参数,当为1的时候则表示按照轴向对每个维度数组进行排序后形成n-1维数组。
线性代数操作
NumPy的数组类型比较类似矩阵,所以也能够进行线性代数的一些操作。与MATLAB比,NumPy的线性代数中*是逐元素乘积而非点积,内置函数np.dot()和特殊符号@可以用来计算点积。这些都是上文提到过的东西。
numpy.linalg拥有一个矩阵分解的标准函数集以及其他的常用函数,比方说求逆和行列式计算。当然这些都是依靠MATLAB和R等语言使用的相同行业标准线性代数库实现的。
懒得举例子了,详情自行移步numpy官方文档线性代数(numpy.linalg) | NumPy
伪随机数生成
np.random能够根据种子高效生成多种概率分布下的样本值数组。
如生成一个4*4的正态分布样本数组:
import numpy as np
arr1 = np.random.normal(size=(4, 4))
print(arr1)
Result:
[[ 1.66200203 -0.51357541 -1.67670695 0.27314883]
[-2.00505611 -0.23725841 0.38121643 0.55178524]
[ 0.36349897 0.62567258 1.29286501 -0.82610735]
[-0.68341192 0.40426395 -0.28042262 0.16147765]]
这种方式比Python内置的random模块快了1个数量级。
函数 | 描述 |
---|---|
seed | 传送种子 |
permutation | 返回一个序列的随机排列或一个乱序的整数范围序列(返回一个新的序列) |
shuffle | 随机排列一个序列(直接排列原序列) |
rand | 从均匀分布中抽取样本 |
randn | 从N(0,1)中抽取样本 |
binomial | 从二项分布中抽取样本 |
normal | 从正态分布中抽取样本 |
beta | 从beta分布中抽取样本 |
chisquare | 从卡方分布中抽取样本 |
gamma | 从伽马分布中抽取样本 |
uniform | 从均匀[0,1)均匀分布中抽取样本 |