NumPy 技巧与实战案例分享:轻松实现数组操作
NumPy(Numerical Python)是 Python 中用于科学计算的基础软件包。它提供了一个强大的多维数组对象 ndarray
,以及用于处理这些数组的各种派生对象(例如,屏蔽数组和矩阵)。此外,NumPy 还包含了用于执行各种数学运算(如线性代数、傅里叶变换和随机数生成)的函数,这些运算通常比纯 Python 实现更高效。
NumPy 的核心优势在于其矢量化操作。这意味着你可以对整个数组执行操作,而无需编写显式的循环。这不仅使代码更简洁、更易读,而且由于 NumPy 在底层使用经过优化的 C 代码,因此执行速度也更快。
本文将深入探讨 NumPy 的各种实用技巧,并通过具体的实战案例来展示如何利用这些技巧轻松实现数组操作,从而提高你的数据处理和分析效率。
1. NumPy 基础:数组创建与属性
1.1 数组创建
NumPy 提供了多种创建数组的方法:
-
array()
函数: 从 Python 列表或元组创建数组。“`python
import numpy as np从列表创建
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1) # 输出: [1 2 3 4 5]从元组创建
arr2 = np.array((6, 7, 8, 9, 10))
print(arr2) # 输出: [ 6 7 8 9 10]创建多维数组
arr3 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr3)输出:
[[1 2 3]
[4 5 6]]
“`
-
zeros()
函数: 创建一个全零数组。“`python
arr_zeros = np.zeros((3, 4)) # 创建一个 3×4 的全零数组
print(arr_zeros)输出:
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
“`
-
ones()
函数: 创建一个全一数组。“`python
arr_ones = np.ones((2, 5)) # 创建一个 2×5 的全一数组
print(arr_ones)输出:
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
“`
-
empty()
函数: 创建一个未初始化的数组(内容是随机的)。python
arr_empty = np.empty((4, 2)) # 创建一个 4x2 的未初始化数组
print(arr_empty) # 输出内容是随机的 -
arange()
函数: 创建一个等差数列数组。python
arr_arange = np.arange(10, 30, 5) # 创建一个从 10 到 30(不包括 30),步长为 5 的数组
print(arr_arange) # 输出: [10 15 20 25] -
linspace()
函数: 创建一个等间隔数列数组。python
arr_linspace = np.linspace(0, 1, 5) # 创建一个从 0 到 1(包括 1),包含 5 个元素的数组
print(arr_linspace) # 输出: [0. 0.25 0.5 0.75 1. ] -
random
模块: 创建随机数组。
“`python
# 创建一个形状为 (2, 3) 的随机数组,元素值在 [0, 1) 之间
random_arr = np.random.rand(2, 3)
print(random_arr)
# 创建一个形状为 (3, 3) 的随机整数数组,元素值在 [1, 10) 之间
random_int_arr = np.random.randint(1, 10, size=(3, 3))
print(random_int_arr)
“`
1.2 数组属性
NumPy 数组具有以下常用属性:
ndim
: 数组的维度(秩)。shape
: 数组的形状(每个维度的大小)。size
: 数组中元素的总数。dtype
: 数组中元素的数据类型。itemsize
: 数组中每个元素占用的字节数。nbytes
: 整个数组占用的总字节数。
“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(“维度:”, arr.ndim) # 输出: 维度: 2
print(“形状:”, arr.shape) # 输出: 形状: (2, 3)
print(“元素总数:”, arr.size) # 输出: 元素总数: 6
print(“数据类型:”, arr.dtype) # 输出: 数据类型: int64 (或 int32,取决于系统)
print(“每个元素字节数:”, arr.itemsize) # 输出: 每个元素字节数: 8 (或 4,取决于系统)
print(“总字节数:”, arr.nbytes) # 输出: 总字节数: 48 (或 24,取决于系统)
“`
2. NumPy 核心:数组索引、切片与迭代
2.1 数组索引
NumPy 数组的索引方式与 Python 列表类似,但功能更强大:
-
单个元素索引: 使用方括号
[]
和元素的索引位置(从 0 开始)。python
arr = np.array([10, 20, 30, 40, 50])
print(arr[0]) # 输出: 10
print(arr[3]) # 输出: 40
print(arr[-1]) # 输出: 50 (负数索引表示从末尾开始) -
多维数组索引: 使用逗号分隔的多个索引值。
python
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[0, 0]) # 输出: 1 (第一行第一列)
print(arr[1, 2]) # 输出: 6 (第二行第三列)
print(arr[2, -1]) # 输出: 9 (第三行最后一列)
2.2 数组切片
切片用于提取数组的子集:
-
一维数组切片: 类似于 Python 列表的切片。
python
arr = np.array([10, 20, 30, 40, 50])
print(arr[1:4]) # 输出: [20 30 40] (从索引 1 到索引 4 之前)
print(arr[:3]) # 输出: [10 20 30] (从开头到索引 3 之前)
print(arr[2:]) # 输出: [30 40 50] (从索引 2 到末尾)
print(arr[::2]) # 输出: [10 30 50] (从开头到末尾,步长为 2) -
多维数组切片: 使用逗号分隔每个维度的切片。
“`python
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[0:2, 1:3])输出:
[[2 3]
[5 6]] (第一行到第二行之前,第二列到第三列之前)
print(arr[:, 1]) # 输出: [2 5 8] (所有行的第二列)
print(arr[1, :]) # 输出: [4 5 6] (第二行的所有列)
“`
2.3 布尔索引
布尔索引是一种强大的技术,它允许你使用布尔数组(True/False 数组)来选择数组中的元素。
“`python
arr = np.array([1, 2, 3, 4, 5, 6])
bool_index = arr > 3 # 创建一个布尔数组,指示哪些元素大于 3
print(bool_index) # 输出: [False False False True True True]
print(arr[bool_index]) # 输出: [4 5 6] (选择布尔数组中为 True 的元素)
更简洁的写法:
print(arr[arr > 3]) # 输出: [4 5 6]
“`
2.4 花式索引
花式索引使用整数数组进行索引。
“`python
arr = np.array([10, 20, 30, 40, 50, 60])
indices = np.array([1, 3, 5]) # 要选择的元素的索引
print(arr[indices]) # 输出: [20 40 60]
多维数组
arr = np.arange(12).reshape((3, 4))
print(arr)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
row = np.array([0, 1, 2])
col = np.array([1, 2, 3])
print(arr[row, col]) # 输出: [ 1 6 11]
“`
2.5 数组迭代
-
for
循环: 可以直接使用for
循环遍历数组的元素。“`python
arr = np.array([1, 2, 3])
for x in arr:
print(x)输出:
1
2
3
“`
-
nditer()
函数:nditer()
函数提供了一种更灵活的迭代方式,可以控制迭代顺序和访问元素的方式。“`python
arr = np.array([[1, 2], [3, 4]])
for x in np.nditer(arr):
print(x)输出:
1
2
3
4
# 使用 order=’F’ 参数按列优先顺序迭代 (Fortran-style order)
for x in np.nditer(arr, order=’F’):
print(x)#使用 op_flags 参数修改元素值
for x in np.nditer(arr, op_flags=[‘readwrite’]):
x[…] = 2 * x
print(arr) #输出[[2,4],[6,8]]
“`
3. NumPy 进阶:数组操作与通用函数
3.1 数组形状操作
-
reshape()
函数: 改变数组的形状(不改变元素)。“`python
arr = np.arange(12) # 创建一个包含 0-11 的一维数组
arr_reshaped = arr.reshape(3, 4) # 将数组重塑为 3×4 的二维数组
print(arr_reshaped)输出:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
arr_reshaped_again = arr.reshape(2, 2, 3) #重塑为三维数组
“` -
ravel()
函数: 将多维数组展平为一维数组。python
arr = np.array([[1, 2, 3], [4, 5, 6]])
arr_flattened = arr.ravel()
print(arr_flattened) # 输出: [1 2 3 4 5 6]
flatten()
的功能与ravel()
相同,不过flatten
返回的是拷贝,而ravel
返回的是视图(view). -
transpose()
函数 /T
属性: 转置数组(交换行和列)。“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])
arr_transposed = arr.transpose()
print(arr_transposed)输出:
[[1 4]
[2 5]
[3 6]]
print(arr.T) # 与 arr.transpose() 效果相同
“`
3.2 数组拼接与拆分
-
concatenate()
函数: 沿指定轴连接多个数组。“`python
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6]])
arr_concatenated = np.concatenate((arr1, arr2), axis=0) # 沿行方向(axis=0)连接
print(arr_concatenated)输出:
[[1 2]
[3 4]
[5 6]]
arr3 = np.array([[7],[8]])
arr_concatenated_axis1 = np.concatenate((arr1,arr3), axis=1) #沿列方向
print(arr_concatenated_axis1)
“` -
vstack()
函数: 垂直堆叠数组(沿行方向)。“`python
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr_stacked = np.vstack((arr1, arr2))
print(arr_stacked)输出:
[[1 2 3]
[4 5 6]]
“`
-
hstack()
函数: 水平堆叠数组(沿列方向)。python
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr_stacked = np.hstack((arr1, arr2))
print(arr_stacked) # 输出: [1 2 3 4 5 6] -
split()
函数: 将数组拆分为多个子数组。“`python
arr = np.arange(9)
arr_split = np.split(arr, 3) # 将数组拆分为 3 个大小相等的子数组
print(arr_split) # 输出: [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]arr = np.arange(12).reshape(3,4)
arr_split_axis1 = np.split(arr, 2, axis=1) #沿着列方向拆分
“` -
hsplit()
和vsplit()
: 分别沿水平和垂直方向拆分数组,相当于split()
中axis
分别设置为1
和0
。
3.3 通用函数 (ufunc)
通用函数(universal functions,简称 ufunc)是对数组进行逐元素运算的函数。NumPy 提供了大量的 ufunc,涵盖了各种数学、三角、逻辑、位运算等操作。
-
算术运算:
+
,-
,*
,/
,**
(幂),//
(整除),%
(取模)。“`python
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])print(arr1 + arr2) # 输出: [5 7 9] (逐元素相加)
print(arr1 * arr2) # 输出: [ 4 10 18] (逐元素相乘)
print(arr1 ** 2) # 输出: [1 4 9] (逐元素求平方)
“` -
比较运算:
==
,!=
,>
,<
,>=
,<=
.“`python
arr1 = np.array([1, 2, 3])
arr2 = np.array([2, 2, 4])print(arr1 == arr2) # 输出: [False True False] (逐元素比较)
print(arr1 < arr2) # 输出: [ True False True]
“` -
数学函数:
np.sin()
,np.cos()
,np.tan()
,np.exp()
,np.log()
,np.sqrt()
,np.abs()
, 等。python
arr = np.array([0, np.pi/2, np.pi])
print(np.sin(arr)) # 输出: [0.0000000e+00 1.0000000e+00 1.2246468e-16] (逐元素计算正弦值)
print(np.sqrt(arr)) # 逐元素计算平方根 -
聚合函数:
np.sum()
,np.mean()
,np.min()
,np.max()
,np.std()
,np.var()
,np.median()
, 等。“`python
arr = np.array([1, 2, 3, 4, 5])print(np.sum(arr)) # 输出: 15 (求和)
print(np.mean(arr)) # 输出: 3.0 (求平均值)
print(np.max(arr)) # 输出: 5 (求最大值)
print(np.std(arr)) # 求标准差
print(np.argmin(arr)) # 返回最小值的索引
“` -
广播 (Broadcasting): 广播是一种强大的机制,它允许 NumPy 在不同形状的数组之间执行算术运算。广播遵循一组规则,NumPy 会自动扩展较小数组的形状,使其与较大数组的形状兼容。
“`python
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([10, 20, 30]) # arr2 会被广播到与 arr1 相同的形状print(arr1 + arr2)
输出:
[[11 22 33]
[14 25 36]]
“`
4. 实战案例
4.1 图像处理:灰度化
假设你有一张彩色图像,你可以使用 NumPy 将其转换为灰度图像。
“`python
from PIL import Image
加载图像
img = Image.open(“color_image.jpg”) # 替换为你的图像文件名
img_array = np.array(img)
提取 RGB 通道
r = img_array[:, :, 0]
g = img_array[:, :, 1]
b = img_array[:, :, 2]
使用 NTSC 亮度公式计算灰度值
gray_array = 0.299 * r + 0.587 * g + 0.114 * b
将灰度值转换为 8 位无符号整数 (0-255)
gray_array = gray_array.astype(np.uint8)
创建灰度图像
gray_img = Image.fromarray(gray_array)
gray_img.save(“gray_image.jpg”) # 保存灰度图像
“`
4.2 数据分析:标准化
在数据分析中,经常需要对数据进行标准化(使数据的均值为 0,标准差为 1)。
“`python
data = np.array([10, 12, 15, 18, 20, 22, 25])
计算均值和标准差
mean = np.mean(data)
std = np.std(data)
标准化
standardized_data = (data – mean) / std
print(standardized_data)
“`
4.3 线性代数:矩阵乘法
“`python
创建两个矩阵
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
矩阵乘法
C = np.dot(A, B) # 或者使用 A @ B (Python 3.5+)
print(C)
输出:
[[19 22]
[43 50]]
求解线性方程组
2x + y = 5
x – y = 1
a = np.array([[2, 1], [1, -1]])
b = np.array([5, 1])
x = np.linalg.solve(a, b)
print(x) # [2. 1.]
“`
4.4 统计分析:计算相关系数
“`python
创建两组数据
x = np.array([1, 2, 3, 4, 5])
y = np.array([2, 3, 1, 5, 4])
计算相关系数
correlation_coefficient = np.corrcoef(x, y)[0, 1]
print(correlation_coefficient)
“`
5. 总结
NumPy 是 Python 数据科学生态系统中的基石。通过掌握 NumPy 的数组操作技巧和通用函数,你可以高效地处理和分析各种类型的数据。本文介绍了 NumPy 的基础知识、核心概念(如索引、切片、迭代、形状操作、数组拼接与拆分)以及通用函数(包括算术运算、比较运算、数学函数、聚合函数和广播)。
此外,本文还通过几个实战案例展示了 NumPy 在图像处理、数据分析和线性代数等领域的应用。希望这些案例能够帮助你更好地理解 NumPy 的实际应用,并启发你在自己的项目中灵活运用 NumPy。
NumPy 的功能非常丰富,本文只是介绍了其中的一部分。要更深入地学习 NumPy,建议你参考 NumPy 的官方文档和教程,并进行大量的实践练习。 随着你对 NumPy 的熟练程度不断提高,你会发现它是一个无比强大的工具,可以大大提升你的数据处理和分析效率。