很多初学 Python 的同学,处理数字、列表数据时,第一反应都是用原生 list 列表。 但一旦数据量大、计算逻辑多,原生列表就会暴露一堆问题:运行慢、代码繁琐、不支持批量运算、多维数据处理困难。而 NumPy 就是为了解决 Python 数值计算痛点而生的核心库。Pandas、Matplotlib、TensorFlow 等热门库,底层全部依赖 NumPy。 可以毫不夸张地说:NumPy 是 Python 数据分析、机器学习、深度学习、科学计算的地基 今天这篇博客带你认识什么是Numpy以及Pandas
numpy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象、各种派生对象(例如掩码数组和矩阵)以及用于对数组进行快速操作的各种方法,包括数学、逻辑、形状操作、排序、选择、I/O 、离散傅里叶变换、基本线性代数、基本统计运算、随机模拟等等。
numpy的部分功能如下:
大多数numpy数组都有一些限制:
| 属性 | 含义 | 示例结果 |
|---|---|---|
.ndim | 数组维度数(轴数) | arr.ndim → 2 二维数组 |
.shape | 数组形状,返回元组 (行数,列数,...) | arr.shape → (2,3) |
.size | 数组元素总个数 | arr.size → 6 |
.dtype | 数组元素数据类型 | arr.dtype → int64 |
.itemsize | 单个元素占用字节数 | int64 → 8 |
.nbytes | 整个数组占用总字节数 | size × itemsize → 48 |
.data | 数组数据缓冲区(很少直接用) | 内存地址对象 |
.flags | 数组内存布局信息(是否 C 连续等) | 对象 |
.strides | 每个轴上,相邻元素间隔字节数 | (24,8) |
pythonimport numpy as np
# 创建二维数组
arr = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(type(arr))
print(arr.ndim) # 纬度,本案例输出:2
print(arr.shape) # 形状,返回元组(行数,列数),本案例输出:(3,3)
print(arr.size) # 元素总个数,本案例输出:9
print(arr.dtype) # 数据类型,本案例输出:int64
print(arr.data) # 数组缓冲区,本案例输出:<memory at 0x107d54450>
print(arr.itemsize) # 每个元素字节数大小,本案例输出:8
print(arr.nbytes) # 这个数组占用总子节数,本案例输出:72
pythondata = [1,2,3]
print(f"原数据地址为:{id(data)}") # 原数据地址为:4426248256
arr1 = np.array(data)
print(f"arr1地址为:{id(arr1)}") # arr1地址为: 4523555792
print(f"数组数据为:{arr1}") # 数组数据为:[1 2 3]
print("-" * 20)
arr2 = np.array(arr1)
print(f"arr2地址为:{id(arr2)}") # arr2地址为:4523555696
print(f"arr2数组数据为:{arr2}") # arr2数组数据为:[1 2 3]
print("-" * 20)
arr3 = np.asarray(arr1)
print(f"arr3地址为:{id(arr3)}") # arr3地址为:4523555792
print(f"arr3数组数据为:{arr3}") # arr3数组数据为:[1 2 3]
需要注意的是,np.empty 并不保证数组元素被初始化为 0,它只是分配内存空间,数组中的元素值是未初始化的,可能是内存中的任意值。 上述3个方法创建的数组元素类型默认都是float64。
pythonarr1 = np.zeros((2, 5)) # 2行5列,初始值为0
print(arr1)
# [[0. 0. 0. 0. 0.]
# [0. 0. 0. 0. 0.]]
arr2 = np.ones_like(arr1) # 创建和arr1形状相同的全1数组
# [[1. 1. 1. 1. 1.]
# [1. 1. 1. 1. 1.]]
arr2 = np.ones_like(arr1) # 创建和arr1形状相同的全1数组
pythonarr1 = np.full((2, 3), 6)
print(arr1)
# [[6 6 6]
# [6 6 6]]
arr2 = np.full_like(arr1, 5)
print(arr2)
# [[5 5 5]
# [5 5 5]]
arange():返回在给定范围内用均匀间隔的值填充的一维数组。
pythonarr1 = np.arange(0, 10, 2) # [0,10),相邻数值间隔为2
print(arr1)
# [0 2 4 6 8]
arr2 = np.arange(0, 10, 3)
print(arr2)
3 [0 3 6 9]
logspace参数说明
| 参数 | 含义 |
|---|---|
start | 起始指数,第一个元素 = base ** start |
stop | 终止指数,最后一个元素 = base ** stop |
num | 生成样本总数,默认 50 |
endpoint | True:包含base**stop;False:不包含,默认 True |
base | 对数底数,默认 10(常用 10、2、e) |
dtype | 输出数组类型,默认浮点 |
pythonarr1 = np.linspace(start=0, stop=10, num=5)
print(arr1)
# [ 0. 2.5 5. 7.5 10. ]
arr2 = np.linspace(start=0, stop=10, num=5, endpoint=False) # 设置endpoint=False,表示不包括stop
print(arr2)
# [0. 2. 4. 6. 8.]
arr3 = np.logspace(start=2, stop=5, num=5, base=2)
print(arr3)
# [ 4. 6.72717132 11.3137085 19.02731384 32. ]
random.rand():返回给定形状的数组,用 [0, 1) 上均匀分布的随机样本填充。random.randint():返回给定形状的数组,用从低位(包含)到高位(不包含)上均匀分布的随机整数填充。random.uniform():返回给定形状的数组,用从低位(包含)到高位(不包含)上均匀分布的随机浮点数填充。random.randn():返回给定形状的数组,用标准正态分布(均值为0,标准差为1)的随机样本填充。pythonarr1 = np.random.rand(2, 3) # 2行3列 [0,1)之间的随机小数填充
print(arr1)
# [[0.48220906 0.9843963 0.77502716]
# [0.86335115 0.84837197 0.33708721]]
arr2 = np.random.randint(0, 10, (2, 3)) # 2行3列, [0,10)之间的随机整数填充
print(arr2)
# [[7 8 2]
# [1 2 3]]
arr3 = np.random.uniform(3, 6, (2, 3)) # 2行3列,[3.6)之间的随机浮点数填充
print(arr3)
# [[5.69275495 3.84857937 3.2899215 ]
# [5.32035519 3.7460973 3.33859905]]
arr4 = np.random.randn(2, 3)
print(arr4)
# [[-2.03654925 -0.50146561 0.4362483 ]
# [-1.90585739 0.94797017 -0.77026926]]
matrix为ndarray的子类,只能生成二维的矩阵。
pythonarr1 = np.matrix("1 2; 3 4")
print(arr1)
# [[1 2]
# [3 4]]
arr2 = np.matrix([[1, 2], [3, 4]])
print(arr2)
# [[1 2]
# [3 4]]
类型代码:dtype 简写字符;注意:NumPy 类型名末尾数字代表比特 bit数,
int32=32bit
| 类型 | 类型代码 | 说明 |
|---|---|---|
bool_ | 'b' | 布尔型,1 字节,取值 True / False |
int8 | 'i1' | 有符号 8 位整数,范围:(-2^7 \sim 2^7-1) → -128 ~ 127 |
int16 | 'i2' | 有符号 16 位整数,-32768 ~ 32767 |
int32 | 'i4' | 有符号 32 位整数 |
int64 | 'i8' | 有符号 64 位整数 |
uint8 | 'u1' | 无符号 8 位整数,0 ~ 255(图像像素最常用) |
uint16 | 'u2' | 无符号 16 位整数,0 ~ 65535 |
uint32 | 'u4' | 无符号 32 位整数 |
uint64 | 'u8' | 无符号 64 位整数 |
float16 | 'f2' | 半精度浮点数 |
float32 | 'f4' | 单精度浮点数 |
float64 | 'f8' | 双精度浮点数(numpy 默认浮点类型) |
complex64 | 'c8' | 复数,实部虚部各 float32 |
complex128 | 'c16' | 复数,实部虚部各 float64 |
str_ | 'U' | Unicode 字符串类型,U5代表最多 5 个字符 |
bytes_ | 'S' | 字节字符串,S3最多 3 个字节 |
object_ | 'O' | Python 对象类型,可以存放任意 Python 对象 |
datetime64 | 'M' | 日期时间类型 |
timedelta64 | 'm' | 时间间隔类型 |
python# 创建数组时可以使用dtype参数指定元素类型:
arr1 = np.array([1, 2, 3], dtype=np.float64)
# [1. 2. 3.]
arr2 = np.array([0.2, 2.5, 4.8], dtype="i8")
# [0 2 4]
# 也可以使用ndarray.astype()方法转换数组的元素类型:
arr1 = np.array([1, 2, 3], dtype=np.float64)
# [1. 2. 3.]
arr2 = arr1.astype(np.int64)
# [1 2 3]
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。 可以通过内置的slice函数,或者冒号设置start, stop及step参数进行切片,从原数组中切割出一个新数组。
pythonimport numpy as np
arr = np.arange(10)
print(arr)
# [0 1 2 3 4 5 6 7 8 9]
#获取索引为2的数据
print(arr[2])
# 2
# 从索引 2开始到索引9(不包含)停止,间隔为2
print(arr[slice(2,9,2)])
# [2 4 6 8]
# 从索引2开始到索引9(不包含)停止,间隔为2
print(arr[2:9:2])
# [2 4 6 8]
# 从索引2开始到最后(不包含),默认间隔为1
print(arr[2:])
# [2 3 4 5 6 7 8 9]
# 从索引2开始到索引9(不包含)结束,默认间隔为1
print(arr[2:9])
# [2 3 4 5 6 7 8]
| 函数 | 说明 |
|---|---|
np.abs() | 元素的绝对值,参数是 number 或 array |
np.ceil() | 向上取整,参数是 number 或 array |
np.floor() | 向下取整,参数是 number 或 array |
np.rint() | 四舍六入五成双。小于 5 直接舍去;大于 5 进位;恰好等于 5:看前一位,偶数舍去 5,奇数进位 |
np.isnan() | 判断元素是否为 NaN (Not a Number),参数是 number 或 array |
np.multiply() | 逐元素相乘。传数字:数组全部乘该数字;传数组:对应位置元素相乘,返回同形状新数组 |
np.divide() | 逐元素相除,参数是 number 或 array |
np.where(condition, x, y) | 三元运算符,满足条件取 x,不满足取 y,等价 x if condition else y |
pythonimport numpy as np
# np.abs 绝对值
arr1 = np.array([-2, -1.5, 0, 3.2])
print("np.abs:", np.abs(arr1))
# np.abs: [2. 1.5 0. 3.2]
# np.ceil 向上取整
arr2 = np.array([1.2, 1.5, 1.9, -1.2])
print("np.ceil:", np.ceil(arr2))
# np.ceil: [ 2. 2. 2. -1.]
# np.floor 向下取整
print("np.floor:", np.floor(arr2))
# np.floor: [ 1. 1. 1. -2.]
# np.rint 四舍六入五成双
arr3 = np.array([2.5, 3.5, 2.4, 2.6])
print("np.rint:", np.rint(arr3))
# np.rint: [2. 4. 2. 3.]
# 2.5 → 2(前一位2偶数,舍去5)
# 3.5 → 4(前一位3奇数,进位)
# np.isnan 判断NaN
arr4 = np.array([1, np.nan, 3, np.nan])
print("np.isnan:", np.isnan(arr4))
# np.isnan: [False True False True]
# np.multiply 逐元素相乘
a = np.array([1,2,3])
b = np.array([4,5,6])
print("multiply 数组*数字:", np.multiply(a, 2))
# multiply 数组*数字: [2 4 6]
print("multiply 数组*数组:", np.multiply(a, b))
# multiply 数组*数组: [ 4 10 18]
# np.divide 逐元素相除
print("divide 数组/数字:", np.divide(a, 2))
# divide 数组/数字: [0.5 1. 1.5]
print("divide 数组/数组:", np.divide(a, b))
# divide 数组/数组: [0.25 0.4 0.5 ]
# np.where 三元选择
cond_arr = np.array([1,5,3,8])
res = np.where(cond_arr > 4, cond_arr, 0)
print("np.where(>4取原值否则0):", res)
# np.where(>4取原值否则0): [0 5 0 8]
| 函数 | 说明 |
|---|---|
np.mean() | 所有元素的平均值,可指定 axis 按轴计算 |
np.sum() | 所有元素的和,可指定 axis 按轴计算 |
np.max() | 所有元素的最大值,可指定 axis 按轴计算 |
np.min() | 所有元素的最小值,可指定 axis 按轴计算 |
np.std() | 所有元素的标准差,可指定 axis 按轴计算 |
np.var() | 所有元素的方差,可指定 axis 按轴计算 |
np.argmax() | 最大值的下标索引值,可指定 axis |
np.argmin() | 最小值的下标索引值,可指定 axis |
np.cumsum() | 累积和,返回数组,每个元素是前面所有元素累加 |
np.cumprod() | 累积乘积,返回数组,每个元素是前面所有元素累乘 |
pythonimport numpy as np
# 二维测试数组
arr = np.array([[1, 3, 5],
[2, 4, 6]])
print("原始数组:")
print(arr)
print("-" * 40)
# np.mean 平均值
print("np.mean(arr) 全部元素均值:", np.mean(arr))
# np.mean(arr) 全部元素均值: 3.5
print("np.mean(arr, axis=0) 按列均值:", np.mean(arr, axis=0))
# np.mean(arr, axis=0) 按列均值: [1.5 3.5 5.5]
print("np.mean(arr, axis=1) 按行均值:", np.mean(arr, axis=1))
# np.mean(arr, axis=1) 按行均值: [3. 4.]
# np.sum 求和
print("\nnp.sum(arr) 全部元素和:", np.sum(arr))
# np.sum(arr) 全部元素和: 21
print("np.sum(arr, axis=0) 按列求和:", np.sum(arr, axis=0))
# np.sum(arr, axis=0) 按列求和: [ 3 7 11]
# np.max / np.min
print("\nnp.max(arr) 全局最大值:", np.max(arr))
# np.max(arr) 全局最大值: 6
print("np.min(arr) 全局最小值:", np.min(arr))
# np.min(arr) 全局最小值: 1
print("np.max(arr, axis=1) 每行最大值:", np.max(arr, axis=1))
# np.max(arr, axis=1) 每行最大值: [5 6]
# np.std 标准差 / np.var 方差
print("\nnp.std(arr) 全局标准差:", np.std(arr))
# np.std(arr) 全局标准差: 1.707825127659933
print("np.var(arr) 全局方差:", np.var(arr))
# np.var(arr) 全局方差: 2.9166666666666665
# argmax argmin 索引
print("\nnp.argmax(arr) 全局最大值索引:", np.argmax(arr))
# np.argmax(arr) 全局最大值索引: 5
print("np.argmin(arr) 全局最小值索引:", np.argmin(arr))
# np.argmin(arr) 全局最小值索引: 0
print("np.argmax(arr, axis=0) 每列最大值索引:", np.argmax(arr, axis=0))
# np.argmax(arr, axis=0) 每列最大值索引: [1 1 1]
# cumsum 累积和,cumprod 累乘
print("\nnp.cumsum(arr) 展平后累积和:", np.cumsum(arr))
# np.cumsum(arr) 展平后累积和: [ 1 4 9 11 15 21]
print("np.cumprod(arr) 展平后累乘积:", np.cumprod(arr))
# np.cumprod(arr) 展平后累乘积: [ 1 3 15 30 120 720]
print("np.cumsum(arr, axis=1) 按行累加:")
print(np.cumsum(arr, axis=1))
# np.cumsum(arr, axis=1) 按行累加:
# [[ 1 4 9]
# [ 2 6 12]]
| 函数 | 说明 |
|---|---|
np.any() | 数组中至少有一个元素满足条件,返回 True;全部不满足则 False,支持axis |
np.all() | 数组中所有元素都满足条件,才返回 True;只要有一个不满足则 False,支持axis |
pythonimport numpy as np
arr = np.array([[1, 3, 5],
[2, 4, 6]])
# 构造布尔条件:元素 >3
cond = arr > 3
print("原始数组:")
print(arr)
print("\narr > 3 的布尔数组:")
print(cond)
#arr > 3 的布尔数组:
#[[False False True]
# [False True True]]
# np.any:任意一个为True,结果为True
print("\nnp.any(cond) 全局是否存在大于3的元素:", np.any(cond))
# np.any(cond) 全局是否存在大于3的元素: True
print("np.any(cond, axis=0) 按列,该列是否存在>3:", np.any(cond, axis=0))
# np.any(cond, axis=0) 按列,该列是否存在>3: [False True True]
print("np.any(cond, axis=1) 按行,该行是否存在>3:", np.any(cond, axis=1))
# np.any(cond, axis=1) 按行,该行是否存在>3: [ True True]
# np.all:全部为True,结果才是True
print("\nnp.all(cond) 全局是否全部大于3:", np.all(cond))
# np.all(cond) 全局是否全部大于3: False
print("np.all(cond, axis=0) 按列,该列全部>3:", np.all(cond, axis=0))
# np.all(cond, axis=0) 按列,该列全部>3: [False False True]
print("np.all(cond, axis=1) 按行,该行全部>3:", np.all(cond, axis=1))
# np.all(cond, axis=1) 按行,该行全部>3: [False False]
| 函数 | 作用 |
|---|---|
np.sort() | 返回排序后的新数组,默认升序 |
np.argsort() | 返回排序后的索引(不改变原值) |
arr.sort() | 原地排序,直接修改原数组,无返回值 |
python# ========== 排序函数演示 ==========
nums = np.array([3,1,9,4,2])
s1 = np.sort(nums)
idx = np.argsort(nums)
print("np.sort:", s1)
# np.sort: [1 2 3 4 9]
print("argsort排序索引:", idx)
# argsort排序索引: [1 4 0 3 2]
print("用索引还原排序:", nums[idx])
# 用索引还原排序: [1 2 3 4 9]
# 原地sort
nums2 = np.array([6,2,5])
nums2.sort()
print("原地sort后nums2:", nums2)
# 原地sort后nums2: [2 5 6]
| 函数 | 作用 |
|---|---|
np.unique() | 获取数组唯一元素,默认返回排序后的去重数组 |
np.unique(arr, return_index=True) | 返回去重数组 + 首次出现的索引 |
np.unique(arr, return_inverse=True) | 返回去重数组 + 原数组映射索引(可还原原数组) |
np.unique(arr, return_counts=True) | 返回去重数组 + 每个元素出现次数 |
python#%%
# ========== 去重函数演示 ==========
data = np.array([2,3,2,5,3,2,7])
uni = np.unique(data)
print("unique去重:", uni)
# unique去重: [2 3 5 7]
# return_index
uni_val, idx = np.unique(data, return_index=True)
print("unique+return_index 值:", uni_val, "首次索引:", idx)
# unique+return_index 值: [2 3 5 7] 首次索引: [0 1 3 6]
# return_inverse
uni_val, inv = np.unique(data, return_inverse=True)
print(uni_val,"inverse索引:", inv ,"还原原数组:", uni_val[inv])
# [2 3 5 7] inverse索引: [0 1 0 2 1 0 3] 还原原数组: [2 3 2 5 3 2 7]
# return_counts
uni_val, cnt = np.unique(data, return_counts=True)
print("元素计数:", cnt)
# 元素计数: [3 2 1 1]
umpy中的数组不用编写循环即可执行批量运算,称之为矢量化运算。大小相等的数组之间的任何算术运算都会将运算应用到元素级。
pythonimport numpy as np
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[7, 8, 9], [10, 11, 12]])
print(arr1 + arr2)
# [[ 8 10 12]
# [14 16 18]]
print(arr1 - arr2)
# [[-6 -6 -6]
# [-6 -6 -6]]
print(arr1 * arr2)
# [[ 7 16 27]
# [40 55 72]]
print(arr1 / arr2)
# [[0.14285714 0.25 0.33333333]
# [0.4 0.45454545 0.5 ]]
数组与标量的算术运算会将标量值传播到各个元素,不同大小的数组之间的运算叫做广播。
python#%%
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1 + 100)
# [[101 102 103]
# [104 105 106]]
print(arr1 - 100)
print(arr1 * 100)
print(arr1 / 100)
广播机制是 NumPy 中一个强大的特性,它允许在不同形状的数组之间进行元素级运算。广播机制的规则如下:
pythonimport numpy as np
# 一维数组
arr1 = np.array([1, 2, 3]) # 形状为 (3,) 这是个元组,元组只有一个元素,表示 1个数组里有3个元素
# 二维数组
arr2 = np.array([[4], [5], [6]]) # 形状为 (3, 1)
# 对 arr1 应用规则 1,在其形状最左边补 1,变为 (1, 3) [[1,2,3]]
# 此时 arr1 形状 (1, 3) 和 arr2 形状 (3, 1) 满足广播条件
result = arr1 + arr2
print("规则 1 示例结果:\n", result)
# 规则 1 示例结果:
# [[5 6 7]
# [6 7 8]
# [7 8 9]]
pythonimport numpy as np
# 二维数组
arr3 = np.array([[1, 2, 3]]) # 形状为 (1, 3)
# 二维数组
arr4 = np.array([[4], [5], [6]]) # 形状为 (3, 1)
# arr3 沿着第0个维度扩展,将原有的一行数据复制成3行,为 (3, 3)=>[[1,2,3], [1,2,3], [1,2,3]]
# arr4 沿着第1个维度扩展, (3, 3)=>[[4,4,4], [5,5,5], [6,6,6]]
result = arr3 + arr4
print("规则 2 示例结果:\n", result)
#规则 2 示例结果:
# [[5 6 7]
# [6 7 8]
#. [7 8 9]]
pythonimport numpy as np
# 一维数组
arr5 = np.array([1, 2, 3]) # 形状为 (3,)
# 一维数组
arr6 = np.array([4, 5]) # 形状为 (2,)
try:
result = arr5 + arr6
print(result)
except ValueError as e:
print(f"规则 3 示例错误信息:{e}")
# 规则 3 示例错误信息:operands could not be broadcast together with shapes (3,) (2,)
通过*运算符和np.multiply()对两个数组相乘进行的是对位乘法而非矩阵乘法运算。
pythonimport numpy as np
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[6, 5, 4], [3, 2, 1]])
print(arr1 * arr2)
# [[ 6 10 12]
# [12 10 6]]
print(np.multiply(arr1, arr2))
# [[ 6 10 12]
# [12 10 6]]
使用np.dot()、ndarray.dot()、@可以进行矩阵乘法运算。
pythonarr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([[6, 5], [4, 3], [2, 1]])
#对于矩阵乘法来说,要求第一个矩阵的列数等于第二个矩阵的行数
print(arr1)
print(arr2)
print(arr1.shape, arr2.shape) # (2, 3) (3, 2)
print(np.dot(arr1, arr2))
# [[20 14]
# [56 41]]
print(arr1.dot(arr2))
print(arr1 @ arr2)
# 一个二维数组跟一个大小合适的一维数组的矩阵点积运算之后将会得到一个一维数组
arr3 = np.array([6, 5, 4])
print(arr1 @ arr3)
# [28 73]
矩阵乘法的规则是:

结果矩阵中第 i 行第 j 列的元素等于第一个矩阵的第 i 行与第二个矩阵的第 j 列对应元素乘积之和。


结果矩阵第一行第一列的元素:
计算 arr1 的第一行 [1, 2, 3] 与 arr2 的第一列 [6, 4, 2] 对应元素乘积之和,即 16 + 24 + 3*2 = 6 + 8 + 6 = 20。
结果矩阵第一行第二列的元素:
计算 arr1 的第一行 [1, 2, 3] 与 arr2 的第二列 [5, 3, 1] 对应元素乘积之和,即 15 + 23 + 3*1 = 5 + 6 + 3 = 14。
结果矩阵第二行第一列的元素: 计算 arr1 的第二行 [4, 5, 6] 与 arr2 的第一列 [6, 4, 2] 对应元素乘积之和,即 46 + 54 + 6*2 = 24 + 20 + 12 = 56。
结果矩阵第二行第二列的元素: 计算 arr1 的第二行 [4, 5, 6] 与 arr2 的第二列 [5, 3, 1] 对应元素乘积之和,即 45 + 53 + 6*1 = 20 + 15 + 6 = 41。
所以,手动计算得到的结果矩阵是 [[20, 14], [56, 41]]。


本文作者:繁星
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!