Numpy
链接:https://www.bilibili.com/video/BV1tA411H7cQ?p=1
官方文档:https://numpy.org/doc/stable/user/
- 安装
通过pip install numpy
即可安装 - 引入
通过import numpy as np
引入
Numpy中的数组
- numpy中的数组的数据类型必须全部一致
- 数组可以是多维的,相当于矩阵,可进行相互运算
创建数组(np.ndarray对象)
- 使用np.arry来创建数组
a = np.array([1, 2, 3, 4])
print(a)
# [1 2 3 4]
- 使用np.arange创建数组,类似于python中的range()
a = np.arange(10)
print(a)
# [0 1 2 3 4 5 6 7 8 9]
- 使用np.random生成随机数数组
a1 = np.random.random((2, 2)) # 生成2行2列的0~1随机数数组
a2 = np.random.randint(0, 10, size=(3, 3)) # 生成3行3列0~10之间的整数
- 使用函数生成特殊的数组
a1 = np.zeros((2, 2)) # 生成2x2的全是0的数组
a2 = np.ones((3, 2)) # 生成3x2的全是1的数组
a3 = np.full((3, 3), 8) # 生成3x3的全是8的数组
a4 = np.eye(3) # 生成3x3的单位矩阵
数组常用属性
ndarray.dtype
数组中只能存储同一种数据类型,可以通过dtype获取数组中元素的数据类型。一下是常用数据类型:
数据类型 | 描述 | 唯一标识符 |
---|---|---|
bool | 用一个字节存储的布尔类型(True或False) | ‘b’ |
int8 | 一个字节大小,-128至127 | ‘i1’ |
int16 | 16位整数,-215至215-1 | ‘i2’ |
int32(默认) | 32位整数,-231至231-1 | ‘i4’ |
int64 | 64位整数,-263至263-1 | ‘i8’ |
uint8 | 无符号整数,0至255 | ‘u1’ |
uint16 | 无符号整数,0至216-1 | ‘u2’ |
uint32 | 无符号整数,0至232-1 | ‘u4’ |
uint64 | 无符号整数,0至264-1 | ‘u8’ |
float16 | 16位半精度浮点数 | ‘f2’ |
float32 | 32位单精度浮点数 | ‘f4’ |
float64 | 64位双精度浮点数 | ‘f8’ |
complex64 | 复数,分别用两个32位浮点数表示实部虚部 | ‘c8’ |
complex128 | 复数,分别用两个64位浮点数表示实部虚部 | ‘c16’ |
object_ | python对象 | ‘O’ |
string_ | 字符串 | ‘S’ |
unicode_ | unicode类型 | ‘U’ |
- 指定dtype
a = np.array([1, 2, 3], dtype=np.int8)
# 或a = np.array([1, 2, 3], dtype='i1')
print(a.dtype)
# int8
- 使用ndarray.astype修改dtype
a = np.array([1, 2, 3])
print(a.dtype) # int32
b = a.astype(np.int8)
print(b.dtype) # int8
- 可以使用ndarray.itemsize获取数组中每个元素的大小,单位是字节
a = np.array([1, 2, 3], dtype=np.int32)
print(a.itemsize) # 4
ndarray.size
获取数组中总的元素的个数:
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a.size) # 9
ndarray.ndim
数组的维度:
a = np.array([1, 2, 3])
print(a.ndim) # 1
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.ndim) # 2
a = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(a.ndim) # 3
ndarray.shape
数组的维度的元组:
a1 = np.array([1, 2, 3])
print(a1.shape) # (3,) 一维数组1x3
a2 = np.array([[1, 2, 3], [4, 5, 6]])
print(a2.shape) # (2, 3) 二维数据2x3
a3 = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(a3.shape) # (2, 2, 3) 三维数组2x2x3
可以通过ndarray.reshape来重新修改数组的维度:
a4 = a3.reshape(2, 6)
print(a4)
# [[ 1 2 3 4 5 6]
# [ 7 8 9 10 11 12]]
Numpy数组操作
索引和切片
- 获取某行的数据
a = np.arange(0, 16).reshape((4, 4))
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]
# [12 13 14 15]]
print(a[1])# 获取下标为1的行的数据
# [4 5 6 7]
print(a[-1])# 可以使用负数索引
# [12 13 14 15]
- 获取几行的数据
a = np.arange(0, 16).reshape((4, 4))
print(a[0:2])# 获取0至1行数据
print(a[[0,2]])# 获取不连续行的数据
- 获取某行某列的数据
a = np.arange(0, 16).reshape((4, 4))
print(a[1, 1])# 获取1行1列的数据
# 5
print(a[0: 2, 0: 2])# 获取0-1行的0-1列数据
# [[0 1]
# [4 5]]
print(a[[0, 2], [0, 2]])# 获取(0,0),(2,2)的两个数据,也叫花式索引
# [0 10]
- 获取某列的数据
a = np.arange(0, 16).reshape((4, 4))
print(a[:, 1])# 获取下标为1的列的数据
# [ 1 5 9 13]
布尔索引
a = np.arange(0, 16).reshape((4, 4))
print(a < 10)# 返回一个元素类型为bool的数组
# [[ True True True True]
# [ True True True True]
# [ True True False False]
# [False False False False]]
如果需要将a中的小于10的元素提取出来:
a = np.arange(0, 16).reshape((4, 4))
print(a[a < 10])
# [0 1 2 3 4 5 6 7 8 9]
其中布尔运算可以有!=,==,<,>,<=,>=以及&(与),|(或)
a = np.arange(0, 16).reshape((4, 4))
print(a[(a < 10) & (a > 5)])
# [6 7 8 9]
值的替换
- 利用索引,将指定位置的值替换成其他值
a = np.arange(0, 16).reshape((4, 4))
a[2] = 0 # 将第3行所有值都替换成0
a[3] = np.array([1, 1, 1, 1]) # 将第3行的所有值替换成[1,1,1,1]
print(a)
# [[0 1 2 3]
# [4 5 6 7]
# [0 0 0 0]
# [1 1 1 1]]
- 利用条件索引来替换
a = np.arange(0, 16).reshape((4, 4))
a[a < 5] = 0
print(a)
# [[ 0 0 0 0]
# [ 0 0 0 0]
# [ 8 9 10 11]
# [12 13 14 15]]
- 利用where函数来实现
a = np.arange(0, 16).reshape((4, 4))
b = np.where(a < 8, 1, 0) # 把所有小于8的变成1,其余的变成0
print(b)
# [[1 1 1 1]
# [1 1 1 1]
# [0 0 0 0]
# [0 0 0 0]]
案例分析:
取出四阶矩阵对角线元素,分别以一维和二维数组的形式。
a=np.arange(0,16).reshape(4,4)
print(a[np.eye(4)==1])
# [ 1 6 11 16]
a[np.eye(4)==0]=0
print(a)
# [[ 1 0 0 0]
# [ 0 6 0 0]
# [ 0 0 11 0]
# [ 0 0 0 16]]
数组的计算(广播机制)
1.数组与数的计算,加减乘除类似
a=np.random.random((3,4))
a1=a*10 # a的所有元素乘10
a2=a.round(2) # 使所有元素保留两位小数
2.数组与数组的运算
1)结构相同的数据之间的计算
a1 = np.arange(0, 4).reshape(2, 2)
a2 = np.eye(2) * 10
a3 = a1 + a2
print(a3)
# [[10. 1.]
# [ 2. 13.]]
2)与列数相同并且只有1行的数组之间的计算:会将每个数分别加到每列。
a1 = np.arange(0, 4).reshape(2, 2)
a2 = np.array([0, 10])
a3 = a1 + a2
print(a3)
# [[ 0 11]
# [ 2 13]]
3)与行数相同并且只有1列的数组之间的计算:会将每个数分别加到每行。
a1 = np.arange(0, 4).reshape(2, 2)
a2 = np.array([[0], [10]])
a3 = a1 + a2
print(a3)
# [[ 0 1]
# [12 13]]
广播原则:
如果两数组的后缘维度(即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为他们是广播兼容的。广播会在缺失和长度为1的维度上进行。
- shape为(3,8,2)的数组能和(8,1)的数组进行运算吗?
能,2和1虽然不相等,但有一方为1,所以能。 - shape为(3,1,4)的数组能和(8,1)的数组进行运算吗?
能,4和1虽然不相等,且1和8不相等,但两项中有一方为1,所以能。
数组形状的操作
reshape和resize方法
1)reshape是返回数组转换成指定形状后的结果,原数组没有发生改变
a = np.random.randint(0, 10, size=(3, 4))
a1 = a.reshape((2, 6))
2)resize是将数组转换成指定形状,会直接修改原数组,不返回任何值
a = np.random.randint(0, 10, size=(3, 4))
a.resize((2, 6))
flatten和ravel方法
都是将多维数组转换为一维数组。
1)flatten是将数组转换为一维数组后,然后将这个拷贝返回回去,所以后续对这个返回值进行修改不会影响之前的数组。
2)ravel是将数组转换为一维数组后,将这个视图(可以理解为引用)返回回去,所以后续对这个返回值进行修改会影响之前的数组。
a = np.arange(0, 12).reshape(3, 4)
a.flatten()[0] = 100 # 此时a[0]位置的元素还是0
a.ravel()[0] = 100 # 此时a[0]位置的元素是100
不同数组的组合
- vstack:将数组按垂直方向进行叠加。数组的列数必须相同才能叠加。
a1 = np.random.randint(0, 10, size=(3, 5))
a2 = np.random.randint(0, 10, size=(1, 5))
a3 = np.vstack([a1, a2])
- hstack:将数组按水平方向进行叠加。数组的行必须相同才能叠加。
a1 = np.random.randint(0, 10, size=(3, 2))
a2 = np.random.randint(0, 10, size=(3, 1))
a3 = np.hstack([a1, a2])
- concatenate([],axis):将两个数组进行叠加,但是具体是按水平方向还是按垂直方向。则要看axis的参数,如果axis=0,那么代表的是往垂直方向(行)叠加,如果axis=1,那么代表的是往水平方向(列)上叠加,如果axis=None,那么会将两个数组组合成一个一维数组。
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
c1=np.concatenate((a, b), axis=0)
print(c1)
# [[1 2]
# [3 4]
# [5 6]]
c2=np.concatenate((a, b.T), axis=1)
print(c2)
# [[1 2 5]
# [3 4 6]]
c3=np.concatenate((a, b), axis=None)
print(c3)
# [1 2 3 4 5 6]
数组的切割
- hsplit:按照水平方向进行切割。用于指定分割成几列,可以使用数字来代表分成几部分,也可以使用数组来代表分割的地方。
a = np.arange(0, 8).reshape(2, 4)
b = np.hsplit(a, 2) # 分割成两部分
print(b)
# [array([[0, 1],
# [4, 5]]),
# array([[2, 3],
# [6, 7]])]
c = np.hsplit(a, [1, 2])#代表在下标为1和2的地方分别切一刀,分成三部分
print(c)
# [array([[0],
# [4]]),
# array([[1],
# [5]]),
# array([[2, 3],
# [6, 7]])]
- vsplit:按照垂直方向进行切割。用于指定分割成几行,可以使用数字来代表分成几部分,也可以使用数组来代表分割的地方。
a = np.arange(0, 16).reshape(4, 4)
b = np.vsplit(a, 2) # 分割成两部分
print(b)
# [array([[0, 1, 2, 3],
# [4, 5, 6, 7]]),
# array([[ 8, 9, 10, 11],
# [12, 13, 14, 15]])]
c = np.vsplit(a, [1, 2])
print(c)
# [array([[0, 1, 2, 3]]),
# array([[4, 5, 6, 7]]),
# array([[ 8, 9, 10, 11],
# [12, 13, 14, 15]])]
- split/array_split(array,indicate_or_seciont,axis):用于指定切割方式,在切割的时候需要指定是按照行还是按照列,axis=1代表按照列,axis=0代表按照行。
a = np.arange(0, 16).reshape(4, 4)
b = np.array_split(a, 2, axis=0)
print(b)
# [array([[0, 1, 2, 3],
# [4, 5, 6, 7]]),
# array([[ 8, 9, 10, 11],
# [12, 13, 14, 15]])]
数组(矩阵)转置
- 通过ndarray.T返回这个数组的转置的结果。
a = np.arange(0, 6).reshape((2, 3))
print(a.T)
# [[0 3]
# [1 4]
# [2 5]]
- 通过transpose方法,这个方法返回的是一个View,即修改返回值,会影响到原来数组。
a = np.arange(0, 6).reshape((2, 3))
b = a.transpose()
print(b)
# [[0 3]
# [1 4]
# [2 5]]
文件操作
文件保存
可以使用np.savetxt来将数组等保存到文件中。
np.savetxt(frame, array, fmt=’%.18e’, delimiter=None)
- frame : 文件、字符串或产生器,可以是.gz或.bz2的压缩文件
- array : 存入文件的数组
- fmt : 写入文件的格式,例如:%d %.2f %.18e
- delimiter : 分割字符串,默认是任何空格
a = np.arange(100).reshape(5, 20)
np.savetxt("a.csv", a, fmt="%d", delimiter=",")
文件读取
可以使用np.loadtxt来将数组等从文件中读取。
np.loadtxt(frame, dtype=np.float, delimiter=None, unpack=False)
- frame:文件、字符串或产生器,可以是.gz或.bz2的压缩文件。
- dtype:数据类型,可选。
- delimiter:分割字符串,默认是任何空格。
- skiprows:跳过前面x行。
- usecols:读取指定的列,用元组组合。
- unpack:如果True,读取出来的数组是转置后的。
b=np.loadtxt("a.csv",dtype=np.int16,delimiter=',',skiprows=1,usecols=(1,2,3),unpack=False)
通用函数
一元函数
函数 | 描述 |
---|---|
np.abs | 绝对值 |
np.sqrt | 开根 |
np.square | 平方 |
np.exp | 计算指数(e^x) |
np.log,np.log10,np.log2,np.log1p | 求以e为底,以10为低,以2为低,以(1+x)为底的对数 |
np.sign | 将数组中的值标签化,大于0的变成1,等于0的变成0,小于0的变成-1 |
np.ceil | 朝着无穷大的方向取整,比如5.1会变成6,-6.3会变成-6 |
np.floor | 朝着负无穷大方向取证,比如5.1会变成5,-6.3会变成-7 |
np.rint,np.round | 返回四舍五入后的值 |
np.modf | 将整数和小数分隔开来形成两个数组 |
np.isnan | 判断是否是nan |
np.isinf | 判断是否是inf |
np.cos,np.cosh,np.sin,np.sinh,np.tan,np.tanh | 三角函数 |
np.arccos,np.arcsin,np.arctan | 反三角函数 |
二元函数
函数 | 描述 |
---|---|
np.add | 加法运算,相当于+ |
np.subtract | 减法运算,相当于- |
np.negative | 负数运算,相当于加个负号 |
np.multiply | 乘法运算,相当于* |
np.divide | 除法运算,相当于/ |
np.floor_divide | 取整运算,相当于// |
np.mod | 取余运算,相当于% |
greater,greater_equal,less,less_equal,equal,not_equal | >,>=,<,<=,=,!=的函数表达式 |
logical_and | &的函数表达式 |
logical_or | \的函数表达式 |
聚合函数
函数名称 | 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 | 计算元素的中位数 |
在使用的时候,可以指定具体哪个轴axis.
布尔数组的函数
函数 | 描述 |
---|---|
np.any | 验证任何一个元素是否为真 |
np.all | 验证所有元素是否为真 |
比如想看下数组中是不是所有元素都为0,那么可以通过以下代码来实现:
np.all(a==0)
# 或者是
(a==0).all()
比如我们想要看数组中是否有等于0的数,那么可以通过以下代码来实现:
np.any(a==0)
# 或者是
(a==0).any()
排序
- np.sort:指定轴进行排序。默认是使用数组的最后一个轴进行排序。还有ndarray.sort(),这个方法会直接影响到原来的数组,而不是返回一个新的排序后的数组。
a = np.random.randint(0,10,size=(3,5))
b = np.sort(a) #按照行进行排序,因为最后一个轴是1,那么就是将最里面的元素进行排序。
c = np.sort(a,axis=0) #按照列进行排序,因为指定了axis=0
- np.argsort:返回排序后的下标值。示例代码如下:
np.argsort(a) #默认也是使用最后的一个轴来进行排序。
- 降序排序:np.sort默认会采用升序排序。如果我们想采用降序排序。那么可以采用以下方案来实现:
# 1. 使用负号
-np.sort(-a)
# 2. 使用sort和argsort以及take
indexes = np.argsort(-a) #排序后的结果就是降序的
np.take(a,indexes) #从a中根据下标提取相应的元素
其他函数补充:
- np.apply_along_axis:沿着某个轴执行指定的函数。示例代码如下:
# 求数组a按行求均值,并且要去掉最大值和最小值。
np.apply_along_axis(lambda x:x[(x != x.max()) & (x != x.min())].mean(),axis=1,arr=a)
- np.linspace:用来将指定区间内的值平均分成多少份。示例代码如下:
# 将0-1分成12分,生成一个数组
np.linspace(0,1,12)
- np.unique:返回数组中的唯一值。
# 返回数组a中的唯一值,并且会返回每个唯一值出现的次数。
np.unique(a,return_counts=True)
其他
Axis理解
通常可以理解为axis=0代表的是行,axis=1代表的是列。
具体来说,最外面的括号代表着 axis=0,依次往里的括号对应的 axis 的计数就依次加 1。如图
操作方式:如果指定轴进行相关的操作,那么他会使用轴下的每个直接子元素的第0个,第1个,第2个…分别进行相关的操作。
x = np.array([[0,1],[2,3]])
# 求x数组在axis=0和axis=1两种情况下的和:
print(x.sum(axis=0))
# [2, 4]
print(x.sum(axis=1))
# [1, 5]
三维以上的数组:
如果以上数组按照axis=0的方式进行相加,得到的结果如下:
如果是按照axis=1的方式进行相加,得到的结果如下:
数据缺失处理
NAN和INF值:
- NAN:Not A Number,不是一个数字,但属于浮点类型。
- INF:Infinity,无穷大,属于浮点类型,一般在除数为0时出现。
注意:NAN和NAN不相等。比如np.NAN != np.NAN这个条件是成立的。
NAN和任何值做运算,结果都是NAN。
删除缺失值
- 删除所有NAN的值,因为删除了值后数组将不知道该怎么变化,所以会被变成一维数组
data = np.random.randint(0, 10, size=(2, 3)).astype(np.float)
data[0, 1] = np.nan
data = data[~np.isnan(data)] # 此时的data会没有nan,并且变成一个1维数组
print(data)
- 删除NAN所在的行
data = np.random.randint(0, 10, size=(3, 5)).astype(np.float)
# 将第(0,1)和(1,2)两个值设置为NAN
data[[0, 1], [1, 2]] = np.NAN
# 获取哪些行有NAN
lines = np.where(np.isnan(data))[0]
# 使用delete方法删除指定的行,axis=0表示删除行,lines表示删除的行号
data1 = np.delete(data, lines, axis=0)
用其他值进行替换
scores = np.loadtxt("nan_scores.csv",skiprows=1,delimiter=",",encoding="utf-8",dtype=np.str)
scores[scores == ""] = np.NAN
scores = scores.astype(np.float)
scores2 = scores.copy()
for x in range(scores2.shape[1]):
score = scores2[:, x]
non_nan_score = score[score == score]
score[score != score] = non_nan_score.mean()
print(scores2.mean(axis=0))