numpy是高性能科学计算和数据分析的基础包。其部分功能如下:
- ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。
- 用于对整组数据进行快速运算的标准数学函数(无需编写循环)。
- 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。
- 线性代数、傅里叶变换和随机数生成功能。
- 用于集成由C/C++和Fortran等语言编写的代码的工具。
- numpy提供了一个简单易用的C API,因此很容易将数据给由低级语言编写的外部库,外部库也能以numpy数组的形式将数据返回给python。这个功能使得python成为一种包装C/C++/Fortran历史代码库的选择,并使被包装库拥有一个动态的、易用的接口。
一、ndarray:一种多维数组对象,一个快速而灵活的大数据集容器。
ndarray是一个通用的同构数据多维容器,即:其中所有元素必须是相同类型的。每一个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组类型的对象,):
1.创建数组的常见函数:
相关代码示例:
import numpy as np
data1=[1,2,3.3,4,5.5,6]
data2=[[1,2,3],[4,5,6],[7,8,9]]
arr1=np.array(data1) #return:array([ 1. , 2. , 3.3, 4. , 5.5, 6. ])
arr2=np.array(data2) #return:array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
arr2.ndim #返回维度:2,表明是二维数组
arr2.shape #返回数组各维度大小:(3,3)
#除非显示说明,np.array会为新建的数组推断出一个较为合适的数据类型,数据类型保存在dtype对象
arr1.dtype # dtype('float64'),表明数组对象类型是float64
arr2.dtype #dtype('int32'),表明数组对象类型是int32
#arange是python内置函数range的数组版:
np.arange(10) #return:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
#以下函数创建数组,数据类型默认为float64
np.zeros((2,3)) #array([[ 0., 0., 0.],[ 0., 0., 0.]])
#当要求数据类型不是float64时,可自己定义数据类型
np.ones((2,3),dtype=np.int) #array([[1, 1, 1],[1, 1, 1]])
np.zeros_like(data2) #return:array([[0, 0, 0],[0, 0, 0],[0, 0, 0]])
#np.empty()返回的不是全0数组,很多情况下,返回的是一些初始化的垃圾值,如下所示
np.empty((3,3,2))
"""
return:
array([[[ 4.67296746e-307, 1.69121096e-306],
[ 1.29061074e-306, 1.69119873e-306],
[ 1.78019082e-306, 8.34441742e-308]],
[[ 1.78022342e-306, 6.23058028e-307],
[ 9.79107872e-307, 6.89807188e-307],
[ 7.56594375e-307, 6.23060065e-307]],
[[ 1.78021527e-306, 8.34454050e-308],
[ 1.11261027e-306, 1.15706896e-306],
[ 1.33512173e-306, 1.21455192e+224]]]) """
#创建一个正方的N*N单位矩阵,(对角线为1,其余为0)
np.eye(3,dtype=np.int) #return:array([[1, 0, 0],[0, 1, 0],[0, 0, 1]])
np.identity(3,dtype=np.int) #return:array([[1, 0, 0],[0, 1, 0],[0, 0, 1]])
#转换数组数据类型
#调用astype无论如何都会创建出一个新的数组(原始数据的拷贝),即时dtype前后并未改变
arr=np.array([1.2,3.4,5.6,-1.3,-5.1,8.8])
arr.astype(np.int) #return:array([ 1, 3, 5, -1, -5, 8])
2、数组与标量之间的运算
数组很重要,因为它使你不用编写循环即可对数据执行批量运算,这通常叫做矢量化。大小相等的数组之间的任何运算都会将运算应用到元素级。(相当于.*)
#相同形状的数组之间的运算
arr=np.array([[1,2,3],[4,5,6]]) #arr=array([[1,2,3],[4,5,6]])
arr*arr #return:array([[ 1, 4, 9],[16, 25, 36]])
arr+arr #return:array([[ 2, 4, 6],[ 8, 10, 12]])
#数组与标量的运算
1/arr #return:array([[ 1.,0.5,0.33333333],[0.25,0.2 ,0.16666667]])
广播:不同形状的数组之间的算术运算:
举个例子:距平化处理:数组的每一列减去列平均值
#产生4*3数组,数组元素满足N~(0,0)正态分布,元素取值范围在-1~1之间
arr=np.random.randn(4,3)
#求列平均值,axis=0代表列
arr.mean(0) #return:array([ 0.07979943, -0.18942553, -0.03965893])
#距平化处理:数组的每一列减去列平均值
demeanded=arr-arr.mean(0)
#此时,可以验证以下demeaned的列平均值应为0
demeanded.mean(0)
#实际值:array([ 1.38777878e-17, 2.77555756e-17, 2.77555756e-17])
#理论值:array([0.,0.,0.])
#产生原因:浮点数(比如float32和float64)只能表示近似的分数值。在复杂计算中,可能会积累一些浮点错误。即:计算过程中可能存在四舍五入,存在误差
广播原则:
广播过程图:
3、切片和索引
数组的索引和切片与python内置的list的索引和切片的功能差不多。
#索引和切片
arr=np.arange(10) #return: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[5] #return:5
arr[5:8] #return:array([5,6,7])
#将一个标量赋给一个切片时,该值会自动传播到整个选区
#与列表最重要的区别在于:数组切片是原始数组的视图,
#这就意味着,数组不会被复制,视图上的改变会直接反映到源数组
arr[5:8]=12 #此时,arr=array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
#获取数组切片的副本
arr[5:8].copy()
二维数组的索引方式:
布尔型索引:
布尔索引的长度必须和被索引的轴长度一致。
#布尔型索引
names=np.array(['Bob','Tom','Lisa','Jane','Bob','Ann','Bob','Jack'])
#names=array(['Bob', 'Tom', 'Lisa', 'Jane', 'Bob', 'Ann', 'Bob', 'Jack'], dtype='<U4')
names=='Bob' #return:array([ True, False, False, False, True, False, True, False], dtype=bool)
data=np.random.randn(8,3)
"""
array([[ 0.64358728, 0.40593921, -1.71040931],
[ 0.63031207, 1.31010391, -0.13103434],
[ 0.65910702, 0.32737274, -1.640117 ],
...,
[ 0.74577169, -0.60670922, -1.38634781],
[ 0.21532584, -1.89709105, 0.23931931],
[ 0.37297124, -0.34103594, -0.52493721]])"""
data[names=='Bob']
"""result:
array([[ 0.64358728, 0.40593921, -1.71040931],
[-0.23807753, 0.21069138, 0.07535347],
[ 0.21532584, -1.89709105, 0.23931931]])"""
#还可与布尔的切片混用
data[names=='Bob',1:] #result:array([[ 0.40593921, -1.71040931],[ 0.21069138, 0.07535347],[-1.89709105, 0.23931931]])
data[names=='Bob',2] #result:array([-1.71040931, 0.07535347, 0.23931931])
#布尔数组设置值
data[data<0]=0
"""result:
array([[ 0.64358728, 0.40593921, 0. ],
[ 0.63031207, 1.31010391, 0. ],
[ 0.65910702, 0.32737274, 0. ],
...,
[ 0.74577169, 0. , 0. ],
[ 0.21532584, 0. , 0.23931931],
[ 0.37297124, 0. , 0. ]])"""
#花式索引:为了特定顺序选取行子集,只需传入一个制定顺序的整数列表或ndarray即可
arr=np.eye(6)
arr[[1,3,5]] #result:array([[ 0., 1., 0., 0., 0., 0.],[ 0., 0., 0., 1., 0., 0.],[ 0., 0., 0., 0., 0., 1.]])
arr[[-1,-2,-3]] #result:array([[ 0., 0., 0., 0., 0., 1.],[ 0., 0., 0., 0., 1., 0.],[ 0., 0., 0., 1., 0., 0.]])
4、数组转置和轴变换
转置是重塑的一种特殊形式,它返回的是源数据的视图(不会进行任何复制操作)。数组不仅有转置方法,还有一个特殊的T属性。在进行矩阵计算时,经常需要用到该操作,比如利用np.dot计算矩阵内积XTX。
对于高维数组,transpose需要得到一个由轴编号组成的元组才能对这些轴进行转置:
#数组的转置和轴对称
arr=np.arange(15).reshape((3,5)) #result:array([[ 0, 1, 2, 3, 4],[ 5, 6, 7, 8, 9],[10, 11, 12, 13, 14]])
#数组的转置
arr.T #result:array([[ 0, 5, 10],[ 1, 6, 11],[ 2, 7, 12],[ 3, 8, 13],[ 4, 9, 14]])
#数组的内积
np.dot(arr.T,arr)
#result:array([[125, 140, 155, 170, 185],[140, 158, 176, 194, 212],[155, 176, 197, 218, 239],[170, 194, 218, 242, 266],[185, 212, 239, 266, 293]])
#高维数组的转置
arr=np.arange(16).reshape((2,2,4))
#result:array([[[ 0, 1, 2, 3],[ 4, 5, 6, 7]],[[ 8, 9, 10, 11],[12, 13, 14, 15]]])
arr.transpose((1,0,2))
#result:array([[[ 0, 1, 2, 3],[ 8, 9, 10, 11]],[[ 4, 5, 6, 7],[12, 13, 14, 15]]])
二、通用函数:快速的元素级数组函数
通用函数(即ufunc)是一种对ndarray中的数据执行元素级运算的函数。你可以将其看做简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量包装器。
部分代码示例:
#通用函数
#一元的通用函数
arr=np.arange(10) #result:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.sqrt(arr) #result:array([0. ,1. ,1.41421356,1.73205081,2.,2.23606798,2.44948974,2.64575131,2.82842712,3.])
np.exp(arr)
#result:array([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])
#二元通用函数
x=np.random.randn(8) #result:array([-1.87242965, -1.68656449, 1.21554972, 0.55987752, -1.14612998,-0.31974718, -0.06502421, -0.24251634])
y=np.random.randn(8) #result:array([-0.33648351, -0.73784657, 1.29292073, -0.45373603, 0.44465589,0.91769987, -0.72260663, -0.27529078])
np.maximum(x,y) #result:array([-0.33648351, -0.73784657, 1.29292073, 0.55987752, 0.44465589,0.91769987, -0.06502421, -0.24251634])
三、利用数组进行数据处理
numpy数组使你可以将许多数据处理任务表述为简洁的数组表达式(否则需要编写循环),用数组表达式代替循环的做法,叫做矢量化。一般来说,矢量化数组运算要比等价的纯python方式快上一两个数量级(甚至更多),尤其是各种数值计算。
1.将条件逻辑表述为数组运算
numpy.where函数是三元表达式 x if condition else y的矢量化版本。
#将条件逻辑表述为数组运算
xarr=np.array([1.1,1.2,1.3,1.4,1.5])
yarr=np.array([2.1,2.2,2.3,2.4,2.5])
cond=np.array([True,False,True,True,False])
result=np.where(cond,xarr,yarr) # array([ 1.1, 2.2, 1.3, 1.4, 2.5])
#或:
arr=np.random.randn(3,3)
#result:array([[-0.05303889, -0.44924906, -1.21463744],[ 0.49446801, 1.34358833, -0.34734868],[-0.25690793, -0.24780854, -1.28707246]])
np.where(arr>0,1,-1)
#result:array([[-1, -1, -1],[ 1, 1, -1],[-1, -1, -1]])
2.数学和统计方法
可以通过数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。sum、mean、以及标准差std等聚合计算(又称约简(reduction)),既可以当做数组的实例方法调用,也可以当做地锅鸡Numpy函数使用:
基本数组统计方法:
部分代码实例:
#数学和统计方法
arr=np.random.randn(2,2) #result:array([[-0.27458291, -2.20095677],[ 0.36414381, -1.03765324]])
arr.mean() #result:-0.78726227534115256
#等效于
np.mean(arr) #result:-0.78726227534115256
arr.sum() #result: -3.1490491013646102
#mean和sum类函数能接受axis参数
#求每一行的平均数
arr.mean(axis=1) #result:array([-1.23776984, -0.33675471])
#求每一列的和
arr.sum(0) #result:array([ 0.0895609, -3.23861 ])
3、用于布尔型数组的方法arr=np.random.randn(100)
#arr中大于0的元素之和
(arr>0).sum() #result:49
bools=np.array([True,False,True,True,False])
#以下两种方法也适用于非布尔型数组,所有非0元素都被当做True
#检测数组中所有值是否都是True
bools.all() #False
#检测数组中是否存在一个或多个True
bools.any() #True
4.排序
#排序
#一维数组排序
arr=np.random.randn(5)
#array([-0.3257218 , -0.56117215, 1.27756328, -1.1332233 , 0.45975236])
arr.sort() #此时,arr=array([-1.1332233 , -0.56117215, -0.3257218 , 0.45975236, 1.27756328])
#多维数组可以在任何一个轴向上(0轴【列】或1轴【行】)进行排序
arr1=np.array([[4,2,5],[1,7,5],[9,0,6]])
#数组每一行都从小到大排序
arr1.sort(1) #arr1=array([[2, 4, 5],[1, 5, 7],[0, 6, 9]])
#数组每一列都从小到大排序
arr1.sort(0) #arr1=array([[0, 4, 5],[1, 5, 7],[2, 6, 9]])
5.唯一化及其他集合逻辑
四、用于数组的文件输入输出
#将数组以二进制形式保存在磁盘
arr=np.arange(10)
#若文件末尾没有扩展名.npy,该扩展名会被自动添加
np.save("some_array",arr)
#读取磁盘上的数据
np.load("some_array.npy") #out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
#将多个数组保存到一个压缩文件中,数组以关键字参数传入即可:
np.s
np.savez("arrays.npz",a=arr,b=arr)
arrays=np.load("arrays.npz")
arrays['b'] #out:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
五、线性代数
部分代码示例:
x=np.array([[1,2,3],[4,5,6]])
y=np.array([[6,23],[-1,7],[8,9]])
x.dot(y) #result:array([[ 28, 64],[ 67, 181]])
#相当于
np.dot(x,y) #result:array([[ 28, 64],[ 67, 181]])
常用线性代数函数:
六、随机数生成
常见numpy.random中部分函数: