NumPy是Python数据分析领域的基础库,以其高效的数组操作和数学计算能力闻名,效率高于list的计算速度。本文基于学习笔记整理,带你快速掌握NumPy的核心功能。如有不足,亲谅解!
import numpy as np
一、Ndarray对象:NumPy的核心数据结构
Ndarray(N-dimensional array)是NumPy中表示多维数组的对象,支持高效的同类型数据存储和计算。
1. Ndarray对象:(类似数学中的行列式)
N维数组对象,是一系列同类型的数据的集合,以0下标开始进行集合中元素的索引。
np.array( list ,dtype=np.数据类型):将列表对象转换为一个数组对象,[ ]则是一维,[ [第一行],[第二行],[……] ]则是二维以此类推。dtype是用来指定存储时候的数据类型。
此处的List对象也可以是range( )生成的序列 np.array( range( n ))
np.arange (起始,结束,步长 ) 直接生成数组对象(一维数组)
ndarray.ndim : 数组的维度
ndarray.shape : 数组的形状(行和列)返回的是元组(行,列)
ndarray.size : 数组的元素数量
ndarray.shape= (行,列),则原来的ndarray对象数组的形状就会发生改变。
ndarray.reshape ( (行,列) ):改变数组的形状,返回ndarray对象。(行列乘积不可变即元素数量不可改变)
ndarray.reshape ( (一维数组的个数,),order=’C’/’F’ ):多维数组转换为一维数组,默认为“C”以行为主的顺序展开,“F”是以列为顺序展开。….flatten (order=’C’/’F’)直接将多维数组转化为一维数组,参数同上理一样。
扩展:(2,3,4):reshape中三维数组传入的参数,2代表块数(所包含的二维数组数),3是行,4是列。
Ndarray.tolist ( ):将数组转换为一个列表并返回。
import numpy as np
# 从列表创建一维/二维数组
arr1 = np.array([1, 2, 3]) # 一维数组
arr2 = np.array([[1, 2], [3, 4]]) # 二维数组
# 使用arange生成连续序列
arr_arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
print(arr2.ndim) # 维度:2
print(arr2.shape) # 形状:(2, 2)
print(arr2.size) # 元素总数:4
# reshape需保持元素总数不变
arr_reshaped = arr2.reshape(4) # 转换为1x4数组:[1, 2, 3, 4]
# 直接修改shape属性(谨慎使用)
arr2.shape = (4,) # 原数组变为一维
2. Ndarray数据类型:数值数据,包括整型,浮点型,复数(complex),布尔数
Int8,uint8(无符号数) int16/64,uint16/64 float16/32/64/128 complex64/128/256 bool
二、数组操作进阶
1. 数组计算
-
广播机制:由于Numpy的广播机制在运算过程中,加减乘除的值被广播到所有的元素上面。即数组的加减乘除是内部所有元素本身的加减乘除。
arr = np.array([1, 2, 3])
print(arr * 2) # [2, 4, 6]
-
数组间运算:同形状的数组对应位置进行计算操作,不同形状的多维数组是不可以进行计算的。但多维数组与一维数组进行计算是可以的,此时是多维数组每一行数据都与一维数组计算(行相同每一行计算,列相同每一列计算)。
2. 轴(Axis)的概念
-
二维数组:
axis=0
表示列方向,axis=1
表示行方向。 -
聚合操作示例:
arr = np.array([[1, 2], [3, 4]])
print(np.sum(arr, axis=0)) # 列求和:[4, 6]
print(np.mean(arr, axis=1)) # 行均值:[1.5, 3.5]
在二维数组上,如下图上,就像是一个坐标系,对0轴的操作是对上面‘刻度’的列上数据操作。
通过轴的指定,就可以只对轴上刻度对应的列或行数据单独处理。不指定轴那就是所有数据一起进行计算。三维数组也是同理。
三维数组要讲究立体感,是对空间上数据进行操作。
在计算的时候可以想象成是每一个坐标轴,分别计算这个轴上面的每一个刻度上的值。
所以在二维数组中,0是对列的操作,1是对行的操作。
三、索引、切片与数值修改
1. 基础操作
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr[1, 0]) # 第2行第1列:4
print(arr[:, 1:3]) # 所有行的第2-3列:[[2,3], [5,6]]
与切片索引类似,左闭右开。
2. 条件修改
# 使用布尔索引
arr[arr > 3] = 0 # 将大于3的元素置0
最后一个是获取索引1行的所有列
数组[行,列](行与列都可以单独使用切片)
当取不连续的多行时,使用列表:
import numpy as np
arr1=np.array([1,2,3])
print(arr1[[0,2]]) #[1 3]
四、数组的数值修改
1. 数值修改操作:
import numpy as np
# 初始化一个4x6的数组
t = np.arange(24).reshape(4,6)
# 1. 修改单行/单列
t[1, :] = 0 # 修改第2行的所有列
t[:, 1] = 0 # 修改所有行的第2列
# 2. 修改连续多行/多列
t[1:3, :] = 0 # 修改第2-3行的所有列
t[:, 1:4] = 0 # 修改所有行的第2-4列
# 3. 修改子矩阵(多行多列)
t[1:4, 2:5] = 0 # 修改第2-4行、第3-5列区域
# 4. 修改不连续的点(通过坐标列表)
t[[0,1], [0,3]] = 0 # 修改(0,0)和(1,3)位置的值
# 5. 条件修改(布尔索引)
t[t < 10] = 0 # 将所有小于10的值置0
数组的逻辑运算符:&,|,~
import numpy as np
t=np.array([1,2,3,4,5,6,7,8,9])
t[(t>2)&(t<8)] #与
t[(t>2)|(t<8)] #或
t[~(t>2)&(t<8)] #非
针对np数组的三目运算符:
五、数组的增删与去重
numpy.append函数:
import numpy as np
# 初始化数组
a = np.array([[1,2,3], [4,5,6]])
# 1. 默认不指定轴(结果展平为一维数组)
print("向数组添加元素(默认展平):")
print(np.append(a, [7,8,9])) # 输出:[1 2 3 4 5 6 7 8 9]
# 2. 沿轴0添加(行方向,需列数一致)
print("\n沿轴0添加元素:")
print(np.append(a, [[7,8,9]], axis=0))
# 输出:
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
# 3. 沿轴1添加(列方向,需行数一致)
print("\n沿轴1添加元素:")
print(np.append(a, [[5,5,5], [7,8,9]], axis=1))
# 输出:
# [[1 2 3 5 5 5]
# [4 5 6 7 8 9]]
0添加行,1添加列
numpy.insert函数:
import numpy as np
# 初始化数组
a = np.array([[1,2], [3,4], [5,6]])
# 1. 未指定轴(先展平再插入)
print("未传递 Axis 参数(展平后插入):")
print(np.insert(a, 3, [11,12])) # 在索引3位置插入11,12
# 输出:[ 1 2 3 11 12 4 5 6]
# 2. 沿轴0插入(行方向)
print("\n沿轴0广播插入:")
print(np.insert(a, 1, [11], axis=0)) # 在第1行插入[11, 11](自动广播)
# 输出:
# [[ 1 2]
# [11 11]
# [ 3 4]
# [ 5 6]]
# 3. 沿轴1插入(列方向)
print("\n沿轴1广播插入:")
print(np.insert(a, 1, 11, axis=1)) # 在第1列插入11
# 输出:
# [[ 1 11 2]
# [ 3 11 4]
# [ 5 11 6]]
numpy.delete
函数:删除数组元素或子数组
函数说明
-
功能:返回从输入数组中删除指定子数组的新数组。
-
关键参数:
-
arr
:输入数组。 -
obj
:要删除的索引、切片或索引列表。 -
axis
:指定删除的轴,默认为None
(展平后操作)。
-
import numpy as np
# 初始化一个3x4的数组
a = np.arange(12).reshape(3, 4)
print("第一个数组:")
print(a)
# 输出:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 1. 未指定轴(先展平后删除第5个元素)
print("\n未传递 Axis 参数(展平后删除):")
print(np.delete(a, 5))
# 输出:[ 0 1 2 3 4 6 7 8 9 10 11](删除了索引5的元素5)
# 2. 沿轴1删除列(删除每一行的第2列)
print("\n删除每一行中的第二列:")
print(np.delete(a, 1, axis=1))
# 输出:
# [[ 0 2 3]
# [ 4 6 7]
# [ 8 10 11]]
2. 去重
numpy.unique
函数:数组去重与索引映射
函数说明
-
功能:返回去重后的数组,并支持返回原数组的索引、反向索引和元素计数。
-
关键参数:
-
return_index
:返回去重元素在原数组中的首次出现位置。 -
return_inverse
:返回原数组元素在去重数组中的索引。 -
return_counts
:返回去重元素在原数组中的出现次数。
-
import numpy as np
# 初始化数组
a = np.array([5, 2, 6, 2, 7, 5, 6, 8, 2, 9])
print("第一个数组:")
print(a) # 输出:[5 2 6 2 7 5 6 8 2 9]
# 1. 基本去重
u = np.unique(a)
print("\n去重后的数组:")
print(u) # 输出:[2 5 6 7 8 9]
# 2. 返回去重元素的首次出现索引
u, indices = np.unique(a, return_index=True)
print("\n去重元素在原数组中的首次出现索引:")
print(indices) # 输出:[1 0 2 4 7 9]
# 解释:2首次出现在索引1,5在索引0,6在索引2,依此类推
# 3. 返回反向索引(原数组元素在去重数组中的位置)
u, inverse = np.unique(a, return_inverse=True)
print("\n原数组元素在去重数组中的索引:")
print(inverse) # 输出:[1 0 2 0 3 1 2 4 0 5]
# 4. 返回元素出现次数
u, counts = np.unique(a, return_counts=True)
print("\n去重元素的出现次数:")
print(counts) # 输出:[3 2 2 1 1 1]
# 解释:2出现3次,5出现2次,依此类推
六、数学计算与统计
一、统计函数
1. 极值计算:np.max
/ np.min
import numpy as np
score = np.array([[80, 88], [82, 81], [75, 81]])
# 全局最大值
max_all = np.max(score) # 88
# 沿轴0(列方向)的最大值
max_axis0 = np.max(score, axis=0) # [82, 88]
# 全局最小值
min_all = np.min(score) # 75
# 沿轴0(列方向)的最小值
min_axis0 = np.min(score, axis=0) # [75, 81]
2. 均值与标准差
# 全局均值
mean_all = np.mean(score) # 81.0
# 沿轴0(列方向)的均值
mean_axis0 = np.mean(score, axis=0) # [79.0, 83.0]
# 沿轴0(列方向)的标准差
std_axis0 = np.std(score, axis=0) # [3.60555128, 3.60555128]
3. 极差计算:np.ptp
# 全局最大值与最小值的差(极差)
range_all = np.ptp(score) # 13(88-75)
# 沿轴0的极差
range_axis0 = np.ptp(score, axis=0) # [7, 7]
4. 索引获取:np.argmin
/ np.argmax
# 沿轴0的最小值索引
argmin_axis0 = np.argmin(score, axis=0) # [2, 2](第3行的索引为2)
二、累计操作与广播
1. 累计和:np.cumsum
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 沿轴0(列方向)累计和
cumsum_axis0 = arr.cumsum(axis=0)
# [[1, 2, 3],
# [5, 7, 9]](第二行=原第一行+第二行)
# 沿轴1(行方向)累计和
cumsum_axis1 = arr.cumsum(axis=1)
# [[1, 3, 6],
# [4, 9, 15]]
2. 元素级比较:np.maximum
/ np.minimum
# 元素级比较(支持广播)
result1 = np.maximum([-2, -1, 0, 1, 2], 0) # [0, 0, 0, 1, 2]
result2 = np.minimum([-2, -1, 0, 1, 2], 0) # [-2, -1, 0, 0, 0]
result3 = np.maximum([-2, 5, 0], [1, 2, 3]) # [1, 5, 3]
三、通用数学函数
1. 基础运算
arr = np.array([4, 9, 16])
# 平方根
sqrt_arr = np.sqrt(arr) # [2., 3., 4.]
# 平方
square_arr = np.square(arr) # [16, 81, 256]
# 绝对值
abs_arr = np.abs(np.array([-1, -2, 3])) # [1, 2, 3]
# 指数
exp_arr = np.exp([1, 2, 3]) # [2.718, 7.389, 20.085]
2. 对数与取整
# 自然对数
log_arr = np.log([1, np.e, np.e**2]) # [0, 1, 2]
# 向上取整
ceil_arr = np.ceil([1.2, 2.5, 3.7]) # [2., 3., 4.]
# 向下取整
floor_arr = np.floor([1.2, 2.5, 3.7]) # [1., 2., 3.]
# 四舍五入
rint_arr = np.rint([1.2, 2.5, 3.7]) # [1., 2., 4.]
3. 三角函数与符号处理
# 正弦值
sin_arr = np.sin(np.pi/2) # 1.0
# 符号分离(整数和小数部分)
frac, int_part = np.modf([1.5, 2.3]) # frac=[0.5, 0.3], int_part=[1., 2.]
# 符号复制
copysign_arr = np.copysign([1, -2, 3], [-1, 1, -1]) # [-1, 2, -3]
四、元素级运算与逻辑比较
1. 算术运算
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# 元素级加减乘除
add = np.add(a, b) # [5, 7, 9]
subtract = np.subtract(b, a) # [3, 3, 3]
multiply = np.multiply(a, b) # [4, 10, 18]
divide = np.divide(b, a) # [4.0, 2.5, 2.0]
2. 逻辑比较
x = np.array([1, 3, 5])
y = np.array([2, 3, 4])
# 元素级比较
greater = np.greater(x, y) # [False, False, True]
equal = np.equal(x, y) # [False, True, False]
# 逻辑运算
logical_and = np.logical_and(x > 2, y < 4) # [False, True, False]
七、数组的拼接
1.np.concatenate
:沿指定轴拼接数组
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# 沿轴0(行方向)拼接
result_axis0 = np.concatenate((a, b), axis=0)
# 输出:
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# 沿轴1(列方向)拼接
result_axis1 = np.concatenate((a, b), axis=1)
# 输出:
# [[1 2 5 6]
# [3 4 7 8]]
2. np.stack
:创建新维度堆叠数组
# 沿新维度(轴0)堆叠
stack_axis0 = np.stack((a, b), axis=0)
# 输出形状:(2, 2, 2)
# [[[1 2]
# [3 4]]
# [[5 6]
# [7 8]]]
# 沿列方向(轴1)堆叠
stack_axis1 = np.stack((a, b), axis=1)
# 输出形状:(2, 2, 2)
# [[[1 2]
# [5 6]]
# [[3 4]
# [7 8]]]
3. 快速拼接函数:vstack
与hstack
v1 = np.array([[0,1,2,3,4,5], [6,7,8,9,10,11]])
v2 = np.array([[12,13,14,15,16,17], [18,19,20,21,22,23]])
# 垂直拼接(等价于axis=0的concatenate)
result_v = np.vstack((v1, v2))
# 输出:
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
# 水平拼接(等价于axis=1的concatenate)
result_h = np.hstack((v1, v2))
# 输出:
# [[ 0 1 2 3 4 5 12 13 14 15 16 17]
# [ 6 7 8 9 10 11 18 19 20 21 22 23]]
八、数组的分割
1.使用np.split()
函数分割数组
np.split()
函数是Numpy库中用于分割数组的一个非常强大的工具。它允许你按照指定的轴和位置(或数量)来分割数组。
import numpy as np
# 创建一个3x3的数组
arr = np.arange(9).reshape(3, 3)
print("原数组:")
print(arr)
# 将数组分为三个大小相等的子数组(沿着默认轴0,即横向分割)
b = np.split(arr, 3)
print("\n将数组分为三个大小相等的子数组:")
for i, sub_arr in enumerate(b):
print(f"子数组 {i+1}:\n{sub_arr}")
原数组:
[[0 1 2]
[3 4 5]
[6 7 8]]
将数组分为三个大小相等的子数组:
子数组 1:
[[0 1]
[3 4]]
子数组 2:
[[2]]
子数组 3:
[[5 6]
[7 8]]
注意:在上面的代码中,由于数组arr
的形状是3x3,而我们要将其分割成3个子数组,因此最后一个子数组的形状与其他两个不同。这是因为np.split()
函数在分割时会尽量保持每个子数组的大小相等,但如果无法完全平均分割,则会创建一个形状不同的子数组来容纳剩余的元素。
另外,np.split()
函数还可以接受一个整数数组作为indices_or_sections
参数,以指定分割的具体位置。例如,np.split(arr, [1, 2])
会将数组arr
在索引1和2处分割成三个子数组。
2. 使用numpy.hsplit()
函数水平分割数组
numpy.hsplit()
函数是专门用于水平分割数组的函数,即沿着轴0(横向)分割。它接受一个数组和一个整数作为参数,指定要返回的相同形状的数组数量。
# 创建一个2x6的随机数组
harr = np.floor(10 * np.random.random((2, 6)))
print("\n原数组:")
print(harr)
# 将数组水平分割成3个子数组
split_harr = np.hsplit(harr, 3)
print("\n拆分后:")
for i, sub_arr in enumerate(split_harr):
print(f"子数组 {i+1}:\n{sub_arr}")
注意:
由于np.random.random()
生成的是随机浮点数,因此每次运行代码时得到的数组都会不同。上面的代码示例中使用了np.floor()
函数来将浮点数向下取整,以便得到整数数组。
3. 使用numpy.vsplit()
函数垂直分割数组
numpy.vsplit()
函数与numpy.hsplit()
函数类似,但它是用于垂直分割数组的函数,即沿着轴1(纵向)分割。
# 创建一个4x4的数组
a = np.arange(16).reshape(4, 4)
print("\n原数组:")
print(a)
# 将数组垂直分割成2个子数组
split_a = np.vsplit(a, 2)
print("\n拆分后:")
for i, sub_arr in enumerate(split_a):
print(f"子数组 {i+1}:\n{sub_arr}")
九、数组中的nan和inf
1. nan代表的是空值,inf代表的是无穷值(无穷大/无穷小)
因为np.nan!=np.nan返回的是真(1),np.nan==np.nan返回的是假(0),那么我们就可以让数组与自身比较,不相等时返回的是真值,说明此处是nan。
当一列数据有nan时,如果需要它来计算,则可以替换为平均值。
t.shape返回的是形状,是由元组构成(行,列),此处是获取列数。
np.count_nonzero()返回数组中非0的个数,此处如果不是返回0就说明有nan。
十、数组的转置(a.T)