Numpy基础:数组和矢量计算
Numpy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。它是Pandas等高级工具的构建基础。
部分功能如下:
● ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。
● 用于对整体数组进行快速运算的标准数学函数。
● 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。线性代数、随机数生成以及傅里叶变换功能。
● 可用于集成由C、C++、Fortran等语言编写的代码的工具。
● 用于数据整理和清理、子集构造和过滤、转换等快速的矢量化数组运算。
● 常用的数组算法如排序、唯一化、集合运算等。
● 高效的描述统计和数据聚合/摘要运算。
● 用于异构数据的合并/连接运算的数据对齐和关系型数据运算。
● 数据的分组运算(聚合、转换、函数应用等)。
Numpy的ndarray:多维运算对象
NumPy最重要的的特点为其N维数组对象(即ndarray),该对象是一个快速且灵活的大数据容器。可以利用这种数组对整块数据执行一些数学运算,其语法跟标量元素之间运算一样(在Pycharm-Py3.6环境下运行):
import numpy as np data = [[0.9526,-0.246,-0.8856],[0.5639,0.2379,0.9104]] data = np.array(data) print(data,'\n',data*10,'\n',data + data)
结果:[[ 0.9526 -0.246 -0.8856] [ 0.5639 0.2379 0.9104]], [[ 9.526 -2.46 -8.856] [ 5.639 2.379 9.104]] , [[ 1.9052 -0.492 -1.7712] [ 1.1278 0.4758 1.8208]]
ndarray是一个通用的同构数据多维容器,其中所以的元素必须是相同的类型的。每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(说明数组数据类型的对象):
print(data.shape,'\n',data.dtype)
Data shape: (2, 3) Data Dtype: float64
创建ndarray
创建数组最简单的就是使用array函数,上面代码已使用。它接受一切序列型的对象(包括其他数组),然后产生一个Numpy数组。
import numpy as np data1 = [6,7.5,8.1,0,-1] arr1 = np.array(data1) print(arr1)
[ 6. 7.5 8.1 0. -1. ]
嵌套序列(比如一组等长列表组成的列表)将会被转换为一个多维数组:
data2 = [[1,2,3,4],[5,6,7,8]] arr2 = np.array(data2) print(arr2,'\narr1.dtype:',arr1.dtype,'\narr2.datype:',arr2.dtype)
[[1 2 3 4] [5 6 7 8]] arr1.dtype: float64 arr2.datype: int32
除去np.array之外,还有一些函数也可以新建数组。比如zeros和ones可以创建指定长度或形状的全0或全1数组。empty可以创建一个没有任何具体值的数组。
print('zeros(5):',np.zeros(5),'\nzeros((3,6)):',np.zeros((3,6)),'\nempty(2,3,2):',np.empty((2,3,2)))#这里的(3,6)为3个数组,每个数组里面6个元素,empty中的((2,3,2))代表3维数组
zeros(5): [ 0. 0. 0. 0. 0.] zeros((3,6)): [[ 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0.]] empty(2,3,2): [[[ 6.23042070e-307 4.67296746e-307] [ 1.69121096e-306 1.29061074e-306] [ 1.69119873e-306 1.78019082e-306]] [[ 3.56043054e-307 7.56595733e-307] [ 1.60216183e-306 8.45596650e-307] [ 1.02359645e-306 2.07959376e-312]]]tips:np.empty会返回全0的数组的想法是不安全的。很多情况下,它将返回垃圾值
arange是Python内置函数range的数组版本:
print(np.arange(10))
[0 1 2 3 4 5 6 7 8 9]
函数 | 说明 |
---|---|
array |
将输入数据(列表、元组、数组或其他序列)转换为ndarray。要么推断出dtype,要么显式指定dtype 默认直接复制输入数据 |
asarray | 将输入转换为ndarray,如果输入本是就是一个ndarray就不进行复制 |
arange | 类似于内置的range,但是返回的是一个ndarray而不是列表 |
ones/ones_like | 根据指定的形状和dtype创建一个全1数组。ones_like以另一个数组为参数,并根据其形状和dtype创建一个全1数组 |
zeros/zeros_like | 类似于ones与ones_like |
empty/empty_like | 创建新数组,且只分配内存空间但不填充任何值 |
ndarray的数据类型
dtype(数据类型)是一个特殊的对象,它含有ndarray将一块内存解释为特定的数据类型所需要的信息
arr1 = np.array([1,2,3],dtype = np.float64) arr2 = np.array([1,2,3],dtype = np.int32) print('arr1.type:',arr1.dtype,'\narr2.type:',arr2.dtype)
arr1.type: float64 arr2.type: int32
dtype可以直接映射到相应的机器表示。数值性dtype的命名方式相同:一个类型名(float or int),后面跟一个用于表示各元素位长的数字。
可以通过ndarray的astype方法显式地转换其type:
arr = np.array([1,2,3]) float_arr = arr.astype(np.float64) print('arr.dtype:',arr.dtype,'\nfloat_arr.dtype:',float_arr.dtype)
arr.dtype: int32 float_arr.dtype: float64上述例子将整型转换为浮点数。但是如果浮点数转换为整型的话小数点部分会被截断
arr = np.array([3.7,-1.2,100.21]) print('arr:',arr,'\narrnew:',arr.astype(np.int32))
arr: [ 3.7 -1.2 100.21] arrnew: [ 3 -1 100]
数组与标量之间的运算
数组可以不需要用编写循环即可对数据执行批量运算(也称为矢量化)。大小相等的数组之间的任何运算都会将运算应用到元素级。
如开头的例子:
data = [[0.9526,-0.246,-0.8856],[0.5639,0.2379,0.9104]] data = np.array(data) print(data,'\n',data*10,'\n',data + data)
结果:[[ 0.9526 -0.246 -0.8856] [ 0.5639 0.2379 0.9104]], [[ 9.526 -2.46 -8.856] [ 5.639 2.379 9.104]] , [[ 1.9052 -0.492 -1.7712] [ 1.1278 0.4758 1.8208]]
对于不同大小的数组之间的运算叫做广播。
基本的索引和切片
Numpy数组的索引与Python中的列表功能差不多,且选取数据子集或单个元素的方式很多
arr = np.arange(10) arr[5:8] = 12 print('arr[5]:',arr[5],'\narr[5:8]:',arr[5:8],'\narr[5:9]=12:',arr)
arr[5]: 12 arr[5:8]: [12 12 12] arr[5:9]=12: [ 0 1 2 3 4 12 12 12 8 9]在上述的[5:8]切片中进行赋值计算,其值将会广播到5:8这中间所有值之中
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) print("arr2d[2]:",arr2d[2],'\narr2d[0][2]:',arr2d[0][2])
arr2d[2]: [7 8 9] arr2d[0][2]: 3
对于2维至N维数组来说其arr[][]来对不同的维度进行操作,比如2维数组来说的话arr[0][2]代表的是第一个元组中的第三个元素,对于N维数组的元素选取操作一直只不过是在arr[][][]..n(arr(k1,k2,k3,k4.....kn))进行括号添加。
tips:arr2d[0][2] 相当于 arr2d[0,2]
ndarray的切片语法与python中的切片语法相同。“只有冒号”相当于选取了整个轴
print(arr2d[:,:2])
[[1 2] [4 5] [7 8]]
上面代码表示,选取所有元组中的第1和第2个元素进行输出。
布尔型索引
跟算术运算一样,数组的矢量化也可以延伸至比较运算的矢量化。
names = np.array(['Bob','Eric','King','Tom','Rick','Morty']) print(names=='Rick')
[False False False False True False]#寻找瑞克
arr2d[arr2d <=5] = 0 print('arr2d>3:',arr2d[arr2d >3],'\narr2d:',arr2d)
arr2d>3: [6 7 8 9] arr2d: [[0 0 0] [0 0 6] [7 8 9]]
数组转置和轴对换
转置是重塑的一种特殊形式,它返回的是源数据的视图(没有其他复制操作)数组不仅有transpose方法,还有一个特殊的T属性:
arr = np.arange(15).reshape((3,5)) print("arr:",arr,"\narr.T:",arr.T)
arr: [[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]] arr.T: [[ 0 5 10] [ 1 6 11] [ 2 7 12] [ 3 8 13] [ 4 9 14]]矩阵计算公式->矩阵内积(np.dot)
arr = np.random.randn(6,3) print("矩阵内积:",np.dot(arr.T,arr))
矩阵内积: [[ 4.80746392 1.95976006 -1.24534748] [ 1.95976006 16.00103077 4.91288985] [ -1.24534748 4.91288985 3.00939508]]
通用函数之快速的元素级数组函数
通用函数是对ndarray中的数据执行元素级运算的函数。可以看做简单的函数的矢量包装器。
arr = np.arange(10) print('np.sqrt:',np.sqrt(arr))
np.sqrt: [ 0. 1. 1.41421356 1.73205081 2. 2.23606798 2.44948974 2.64575131 2.82842712 3. ]
print('np.exp:',np.exp(arr))
np.exp: [ 1.00000000e+00 2.71828183e+00 7.38905610e+00 2.00855369e+01 5.45981500e+01 1.48413159e+02 4.03428793e+02 1.09663316e+03 2.98095799e+03 8.10308393e+03]
以上为1维ufunc。下面为二维ufunc代码实例:
x = np.random.randn(8) y = np.random.randn(8) print('元素级最大值(比较两个数组中每个元素的大小且输出最大)'np.maximum(x,y))
x: [-1.12454206 0.44756099 -0.08936177 -0.48088294 -1.14585092 0.31539998 0.73534628 1.73050382] y: [ 1.2063524 0.75194201 0.64254794 0.17197482 -0.54383486 1.15146649 0.64786649 -0.03545039] [ 1.2063524 0.75194201 0.64254794 0.17197482 -0.54383486 1.15146649 0.73534628 1.73050382] #元素级最大值(比较两个数组中每个元素的大小且输出最大)
abs/fabs | 计算整数、浮点数或复数的绝对值 |
sqrt | 计算各元素的平方根 |
square | 计算各元素的平房 |
exp | 计算各元素的指数e^x |
log/log10/log2/log1p | 分别为自然对数底数为e、底数为10、底数为2的log、log(1+x) |
sign | 计算各元素的正负号 |
ceil | 计算各元素的ceiling值(大于等于该值的最小整数) |
floor | 计算各元素的floor值(小于等于该值的最大整数) |
rint | 四舍五入到最接近的整数 |
modf | 将数组的小数与整数部分以独立的数组形式返回 |
isnan | 返回表示缺失值NA的布尔型数组 |
isfinite/isinf | 返回那些元素是有穷的/无穷的的布尔型函数 |
cos/cosh/sin/sinh/tan/tanh | 普通型与双曲型三角函数 |
arccos/arccosh/arcsin | 反三角函数 |
arcsinh/arctan/arctanh | 反三角函数 |
logical_not | 计算各元素not x的真值 |
add | 将数组中的对应的元素相加 |
subtract | 第一个数组的元素减去第二个数组的元素 |
multiply | 数组元素相乘 |
divide/floor_divide | 除法或向下圆整除发(丢弃余数) |
power | 根据A数组的元素与B数组的元素进行A^B计算 |
maximum/fmax | 元素级的最大值计算/fmax忽略NA |
minimum/fmin | 元素级的最小值计算/fmin忽略NA |
mod | 元素的求模计算(除法的余数) |
copysign | 将B组数组的符号赋值给A组数组 |
greater/greater_equal/less/less_equal | 执行元素级的比较运算>,>=,<,<= |
equal/not_equal | 执行元素级的比较运算= ,!= |
logical_and,logical_or,logical_xor | 执行元素级的真值逻辑运算。& ,|,^ |
利用数组进行数据处理
Numpy数组可以将许多数据处理任务表述为简洁的数组表达式。用数组表达式来代替循环的做法,来对各种数值进行计算。
利用sqrt进行计算sqrt(x^2+y^2)。使用np.meshgrid函数接受两个一维数组,并且产生两个二维矩阵
points = np.arange(-5,5,0.01) xs,ys = np.meshgrid(points,points) z = np.sqrt(xs*xs+ys*ys) print(z)
z: [[ 7.07106781 7.06400028 7.05693985 ..., 7.04988652 7.05693985 7.06400028] [ 7.06400028 7.05692568 7.04985815 ..., 7.04279774 7.04985815 7.05692568] [ 7.05693985 7.04985815 7.04278354 ..., 7.03571603 7.04278354 7.04985815]..........
数学和统计方法
可以通过对数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。
arr = np.random.randn(5,4)#正太分布数据 print('arr.mean:',arr.mean(),'\nnp.mean:',np.mean(arr),'\narr.sum:',arr.sum())
arr.mean: 0.283971412332 np.mean: 0.283971412332 arr.sum: 5.67942824663mean和sum这类的函数可以接受axis参数(用于计算该轴向上的统计值)
print('arr.mean:',arr.mean(axis= 1),'\narr.sum:',arr.sum(axis = 0))
arr.mean: [-0.46284488 -0.90444873 0.59768465 0.91953734 -0.4443457 ] arr.sum: [-2.78434202 3.79059117 -4.53320563 2.34928724]
方法 | 说明 |
sum | 对数组中的全部或某轴向的元素求和。零长度的数组sum=0 |
mean | 算术平均数。零长度的数组mean = NA |
std/var | 分别为标准差和方差。*度(df)可以调默认为n |
min/max | 最小值和最大值 |
argmin/argmax | 分别为最大和最小元素的索引 |
cumsum | 所有元素的累计和 |
cumprod | 所有元素的累计积 |
排序与唯一化和其他的集合逻辑
Numpy的数组排序与Python中的列表排序相同,同样适用sort方法进行排序
arr = np.random.randn(8) arr.sort() print('arr:',arr,'\narr.sort():',arr)
arr: [-1.24831884 -0.68584278 -0.47912029 -0.05952106 0.46185154 1.21494395 1.40269136 1.88787154] arr.sort(): [-1.24831884 -0.68584278 -0.47912029 -0.05952106 0.46185154 1.21494395 1.40269136 1.88787154]
Numpy提供了一些针对于一维ndarray的基本集合运算。最常用的为np.unique,其用于找出数组中的唯一值并返回已排序的结果:
arr = np.array([3,3,3,5,5,5,51,1,1,1,-5,-5]) print('arr:',arr,'\narr:',np.unique(arr))
arr: [ 3 3 3 5 5 5 51 1 1 1 -5 -5] arr: [-5 1 3 5 51]
方法 | 说明 |
unique(x) | 计算x中唯一的元素,并返回有序的结果 |
intersect1d(x,y) | 计算x与y中的公共元素,并返回有序结果 |
unicon1d(x,y) | 计算x和y的并集,并返回有序结果 |
in1d | 表示一个‘x的元素是否包含于y’的布尔型函数 |
setdiff1d(x,y) | 集合的差,即元素在x中且不在y中 |
setxor1d(x,y) | 集合的对称差,即存在于一个数组中但不同时存在于两个数组中的元素 |
numpy.where函数是三元表达式x if condition else y的矢量化版本。np.where的第二个与第三个参数不必是数组,都可以为标量值,在数据分析中,where通常用于根据另一个数组而产生一个新的数组。假设一个随机数据组成的矩阵,把正值替换为2,负值替换为-2不需要对行列进行操作,可以用where操作。
arr = np.random.randn(4,4) print(np.where(arr >0,2,-2))
arr: [[-0.09276085 -2.44335478 0.29058974 -0.5304342 ] [ 0.67103892 1.04442429 -0.29126736 -0.13523715] [ 0.0223226 0.60415637 -0.45825663 0.85756563] [ 0.44512035 -1.52816243 -2.1685652 -1.59413984]] np.where(): [[-2 -2 2 -2] [ 2 2 -2 -2] [ 2 2 -2 2] [ 2 -2 -2 -2]]
随机数生成
numpy.random模块对于Python内置的random进行了补充,增加了一些用于高效生成多种概论分布的样本值的函数。
samples = np.random.normal(size=(4,4)) print('samples:',samples)
samples: [[ 0.2893665 0.2981813 -0.17340905 -0.18255428] [-0.0544932 -2.17299399 -0.62735006 0.67073359] [-0.9158938 -0.50018894 1.05703711 -1.76787265] [-0.3772072 -0.62771863 -0.0591299 -0.33709373]]以上为numpy.random生成的正太分布的4X4样本的数组。
函数 | 说明 |
seed | 确定随机数生成器的种子 |
permutation | 返回一个序列的随机排列或返回一个随机排列的范围 |
shuffle | 对一个序列就地随机排列 |
rand | 产生均匀分布的样本值 |
randint | 从给定的上下范围内随机选取整数 |
randn | 产生正太分布(平均值为0,标准差为1)的样本值 |
binomial | 产生二项分布的样本值 |
normal | 产生正太分布的样本值 |
beta | 产生Beta分布的样本值 |
chisquare | 产生卡方分布的样本值 |
gamma | 产生Gamma分布的样本值 |
uniform | 产生在[0,1]中均匀分布的样本值 |