NumPy(Numerical Python)
在某些方面,Numpy数组与Python内置的列表类型非常相似,但是随着数组在维度上变大,Numpy数组提供了更加高效的存储和数据操作。
python中的数据类型
列表的优势是灵活,因为每个列表元素是一个包含数据和类型信息的完整结构体,而且列表可以用任意类型的数据填充。固定数据的NumPy式数组缺乏这种灵活性,但是能更有效地存储和操作数据。
python中的固定类型数组
内置的数组(array)模块可以用于创建统一类型的密集数组。
import array
L = list(range(10))
A = array.array('i',L)
array('i',[0,1,2,3,4,5,6,7,8,9])
#这里的‘i'是一个数据类型码,表示数据为整型
更实用的是Numpy包中的ndarray对象,python的数组对象提供了数组型数据的有效存储,而Numpy为该数据加上了高效的操作。
import numpy as np
np.array([1,2,3,4])
np.array([1,2,3,4],dtype='float32')
#创建一个长度为10的数组,数组的值都是0
In [59]: np.zeros(10,dtype=int)
Out[59]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
#创建一个3*5的数组,数组的值都是1
In [60]: np.ones((3,5),dtype=int)
Out[60]:
array([[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1]])
#创建一个3*5的数值,数组用统一的值进行填充
In [61]: np.full((3,5),3.15)
Out[61]:
array([[3.15, 3.15, 3.15, 3.15, 3.15],
[3.15, 3.15, 3.15, 3.15, 3.15],
[3.15, 3.15, 3.15, 3.15, 3.15]])
#创建一个从0开始,20结束,步长为2的数组
In [62]: np.arange(0,20,2)
Out[62]: array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
#创建一个有5个元素,且元素为等差数列的数组
In [63]: np.linspace(0,1,5)
Out[63]: array([0. , 0.25, 0.5 , 0.75, 1. ])
#创建一个3*3,在0-1之间均匀分布的随机数组组成的数组
In [64]: np.random.random((3,3))
Out[64]:
array([[0.51530173, 0.48086032, 0.72374332],
[0.71859762, 0.28094784, 0.26625239],
[0.10241742, 0.48381546, 0.49666335]])
#创建一个3*3,均值为0,方差为1的正态分布的随机数数组
In [65]: np.random.normal(0,1,(3,3))
Out[65]:
array([[-0.12197335, 0.17629597, 1.35351424],
[ 0.72295497, 0.98907102, -0.44402417],
[-0.07165226, -0.02997592, -1.21310073]])
#创建一个3*3,大于等于0,小于10区间的随机整型数组
In [66]: np.random.randint(0,10,(3,3))
Out[66]:
array([[5, 6, 6],
[8, 8, 6],
[4, 6, 7]])
#创建一个3*3的单位矩阵
In [69]: np.eye(3)
Out[69]:
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
#创建一个有3个整型数组成的未初始化的数组
#数组的值是内存空间中的任意值
In [72]: np.empty(5)
Out[72]: array([0. , 0.25, 0.5 , 0.75, 1. ])
Numpy标准数据类型
当构建一个数组时,你可以用一个字符串参数来指定数据类型
np.zeros(10,dtype=‘int16’)
或
np.zeros(20,dtype=np.int16)
import numpy as np
np.random.seed(0)
x1 = np.random.randint(0,10,size=6)
x2 = np.random.randint(0,10,size=(3,4))
x3 = np.random.randint(0,10,size=(3,4,5))
print(x3.ndim)
print(x3.shape)
print(x3.size)
print(x3.dtype)
数组索引:获取单个元素
在一维数组中可以通过中括号指定索引获取第i个值(从0开始计数):
x1[0]
为了获取数组的末尾索引,可以用负值索引
x1[-1]
在多维数组中,可以用逗号分隔的索引元组获取元素:
x2[0,0]
也可以用上述方式修改元素值:
x2[0,0] = 12
数组切片:获取子数组
x[start:stop:step]
上面3个参数的默认值分别为start=0,stop=维度的大小,step=1
x[::-1]#所有的元素,逆序的
x1[:2,:3]#两行三列
x1[:,0]#获取第一列
x1[0,:]#获取第一行
x1[0]#等于x1[0,:]
关于数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数组数据的副本。这一点也是Numpy数组切片和python列表切片的不同之处。
如果修改子数组,阿么原始数组也会被修改。如果不想原始数组被修改,可以复制原始数组
x1_sub_copy = x2[:2,:2].copy()
数组变形最灵活的实现方式就是通过reshape()
reshape另一个常见的变形模式是将一个一维数组转变为二维的行或列的矩阵。
x.reshape((1,3))
array([[1,2,3]])
x[np.newaxis,:]#第二种方式
数组拼接和分裂
x1 = np.zeros(3,dtype=int)
x2 = np.ones(3,dtype=int)
x_con = np.concatenate([x1,x2])
print(x_con)
#二维数组的拼接
x3 = np.ones((3,3),dtype=int)
print(np.concatenate([x3,x3]))
#沿着固定维度处理数组
#1. 垂直栈数组
x = np.array([1,2,3])
grid = np.arange(4,10)[::-1].reshape(2,3)
v_stack = np.vstack([x,grid])
print(v_stack)
#水平栈数组
grid = np.arange(4,10)[::-1].reshape(2,3)
x = np.full(2,99)[:,np.newaxis]
h_stack = np.hstack([grid,x])
print(h_stack)
#与拼接相反的过程是分裂
#分裂可以通过np.split,np.vsplit,np.hsplit
x = np.array([1,2,3])
x1 = x.copy()[::-1]
x2 = np.full(2,99)
x_con = np.concatenate([x,x2,x1])
print(x_con)
x1,x2,x3 = np.split(x_con,[3,5])
print(x1,x2,x3)
#np.vsplit()
grid = np.arange(16).reshape((4,4))
upper,middle,lower = np.vsplit(grid,[1,3])
print(upper,middle,lower)
Numpy数组的计算:通用函数
使Numpy变快的关键是利用向量化操作,通常在Numpy的通用函数(ufunc)中实现。本节将介绍Numpy通用函数的重要性–它可以提高数组元素的重复计算的效率。
Numpy为很多类型提供了非常方便的、静态类型的、可编译程序的接口,也被称作向量操作。你可以通过简单地对数组执行操作来实现,这里对数组的操作将会用于数组中的每一个元素,这种向量方法被用于将循环推送至Numpy之下的编译层,这样会取得更快的执行效率。
print(np.arange(5)/np.arange(1,6))
x = np.arange(9).reshape((3,3))
print(2**x)
通用函数有两种存在形式:一元通用函数对单个输入操作,二元通用函数对两个输入操作。
Numpy实现的算术运算
运算符 | 对应的通用函数 | 描述 |
---|---|---|
+ | np.add | 加法 |
- | np.subtract | 减法 |
- | np.negative | 负数运算 |
* | np.multiply | 乘法运算 |
/ | np.divide | 除法运算 |
// | np.floor_divide | 地板除法运算 |
** | np.power | 指数运算 |
% | np.mod | 模/余数 |
通用函数
np.absolute()
np.abs()
np.sin()
np.cos()
np.tan()
np.exp()
np.exp2()
np.power(3,x)
np.log()#以e为底
np.log2()
np.log10()
#下面两个函数对很小的输入值可以保持较好的精确度
np.expm1()
np.log1p()
如果你希望对你的数据进行一些更晦涩的数学运算,scipy.special可能包含了你需要的计算函数。
special.gamma()
...
高级的通用函数特性
- 指定输出
x = np.arange(5)
y = np.empty(5)
np.multiply(x,10,out=y)
print(y)
- 聚合
如果我们希望用一个特定的运算reduce一个数组,那么可以用任何通用函数的reduce方法,一个reduce方法会对给定的元素和操作重复执行,直到得到单个的结果。
x = np.arange(1,6)
y = np.add.reduce(x)
z = np.multiply.reduce(x)
print(y)
print(z)
#15
#120
如果需要存储每次计算的中间结果,可以使用accumulate:
y = np.add.accumulate(x)
print(y)
#[ 1 3 6 10 15]
- 外积
任何通用函数都可以用outer方法获得两个不同输入数组所有元素对的函数运算结果。
x = np.arange(1,6)
y = np.multiply.outer(x,x)
print(y)
'''
[[ 1 2 3 4 5]
[ 2 4 6 8 10]
[ 3 6 9 12 15]
[ 4 8 12 16 20]
[ 5 10 15 20 25]]
'''
聚合:最小值、最大值和其他值
#1.
y_min = min(y)
y_max = max(y)
print(y_min)
print(y_max)
#2.
y_min = y.min()
y_max = y.max()
print(y_min)
print(y_max)
#3.
y_min = np.min(y)
y_max = np.max(y)
print(y_min)
print(y_max)
#多维数组
x = np.random.random((3,4))
print(x)
y = np.empty(4)
x.min(axis=0,out=y)
print(y)
#[0.4236548 0.38344152 0.43758721 0.52889492]
#axis=0表示取得每一列的最小值,而axis=1表示取得每一行的最小值
其他聚合函数
y = np.random.random((3,4))
y[1,1] = None
print(y)
y_sum = np.sum(y)
y_sum_safe = np.nansum(y)
print(y_sum)
print(y_sum_safe)
'''
[[0.5488135 0.71518937 0.60276338 0.54488318]
[0.4236548 nan 0.43758721 0.891773 ]
[0.96366276 0.38344152 0.79172504 0.52889492]]
nan
6.832388677914338
'''
函数名称 | NaN安全版本 | 描述 |
---|---|---|
np.sum | np.nansum | 计算元素的和 |
np.prod | np.nanprod | 计算元素的积 |
np.mean | np.nanmean | 计算元素的平均值 |
np.std | np.nanstd | 计算元素的标准差 |
np.var | np.nanvar | 计算元素的方差 |
np.min | np.nanmin | 找出最小值 |
np.max | np.nanmax | 找出最大值 |
np.argmin | np.nanargmin | 找出最小值的索引 |
np.argmax | np.nanargmax | 找出最大值的索引 |
np.median | np.nanmedian | 计算元素的中位数 |
np.percentile | np.nanpercentile | 计算基于元素排序的统计值 |
np.any | N/A | 验证任何一个元素是否为真 |
np.all | N/A | 验证所有元素是否为真 |
import seaborn
seaborn.set()#设置绘图风格
数组的计算:广播
广播用于不同大小数组的二进制通用函数的一组规则。
x = np.array([1,2,3])
sum = x+5
print(sum)
#[6 7 8]
M = np.ones((3,3))
sum = M+x
print(sum)
'''
[[2. 3. 4.]
[2. 3. 4.]
[2. 3. 4.]]
'''
a = np.arange(3)
b = a.copy()[:,np.newaxis]
sum = a+b
print(a)
print(b)
print(sum)
'''
[0 1 2]
[[0]
[1]
[2]]
[[0 1 2]
[1 2 3]
[2 3 4]]
'''
#归一化的操作
x = np.random.random((10,3))
x_mean = np.mean(x,axis=0) #去每一列的均值
x_centered = x - x_mean#减去这个均值实现归一化
x_centered_mean = x_centered.mean(0)#查看归一化的均值是否接近于0
比较操作
x = np.array([1,2,3,4,5])
print(x<3)
print(x>3)
print(x<=3)
print(x>=3)
print(x!=3)
print(x==3)
'''
[ True True False False False]
[False False False True True]
[ True True True False False]
[False False True True True]
[ True True False True True]
[False False True False False]
'''
比较运算符合其对应的通用函数
运算符 | 对应的通用函数 |
---|---|
== | np.equal |
!= | np.not_equal |
< | np.less |
<= | np.less_equal |
> | np.greater |
>= | np.greater_equal |
rng = np.random.RandomState(0)
x = rng.randint(10,size=(3,4))
print(x)
'''
[[5 0 3 3]
[7 9 3 5]
[2 4 7 6]]
'''
#统计布尔数组中true记录的个数
x = np.array([1,2,3,4,5])
y1 = np.count_nonzero(x<3)
y2 = np.sum(x<3)#这个可以沿着行或列进行计算
print(y1)
print(y2)
将布尔数组作为掩码
x = np.random.randint(0,10,(3,4))
print(x)
x_shulf = x<5#对数组进行判断
print(x_shulf)
x_choiced = x[x_shulf]#得到数组中所有小于5的数
print(x_choiced)
and和or判断整个对象是真或假,而&和|是指每个对象中的比特位。bin(number)将数字转换成二进制表示
and 和 or对整个对象执行单个布尔运算,而&和|对一个对象的内容(单个比特或字节)执行多个布尔运算,对于Numpy布尔数组,后者是常用的操作。
花哨的索引
rand = np.random.RandomState(0)
x = rand.randint(100,size=10)
print([x[3],x[7],x[2]])
ind = [3,7,4]#花哨
print(x[ind])
多维数组中花哨的使用
x = np.arange(12).reshape((3,4))
row = np.array([0,1,2])
col = np.array([2,1,3])
x_choiced = x[row,col]
print(x_choiced)
#[ 2 5 11]
排序
如果你想在不修改原始输入数组的基础上返回一个排好序的数组,可以使用np.sort(),如果希望用排好序的数组代替原始数组,可以使用数组的sort:x.sort()
np.argsort(x)返回的是原始数组排好序的索引值。
np.sort()也有axis参数
部分排序:分隔
x = np.array([2,3,5,1,7,4])
x_p = np.partition(x,0)#输出一个新数组,最左边是第K小的值,往右是任意顺序的其他值,这里是搜索第0个小的值。注意,这里索引也是从0开始。这个函数也有axis
print(x_p)
#k近邻
# dist_sq = np.sum((x[:,np.newaxis,:]-x[np.newaxis,:,:])**2,axis=-1)
diff = x[:,np.newaxis,:]-x[np.newaxis,:,:]
diff_diff = diff**2
dist_sq = diff_diff.sum(axis=-1)
dia = dist_sq.diagonal()
nearest = np.argsort(dist_sq)
print(nearest)