哈喽,我是小白~
假期之余,今儿和大家聊聊,NumPy
数组操作的一些技巧!~
在机器学习实验中,NumPy
数组操作技巧能够高效处理和转换大量数据,使得特征工程、数据预处理等步骤更加简洁和快速。它提供了矩阵运算、数组合并、条件筛选等工具,帮助实现复杂的数值计算和数据变换。
通过这些操作,研究者可以优化数据流、提高模型性能,并增强实验的可扩展性。
往期 Numpy 合集
1. 创建数组 (np.array()
)
np.array()
是创建数组的基础函数,用于将普通的 Python 序列(如列表、元组)转换为 NumPy 数组。这是大多数操作的第一步,因为它支持高效的数组操作和计算。
主要功能:
支持多种数据结构:将列表、元组、甚至嵌套的列表转换为数组。 支持指定数据类型:可以通过 dtype
参数指定数据类型(整数、浮点数等)。支持多维数组:不仅限于一维数组,还可以轻松创建多维数组。
Python 实现
import numpy as np
# 创建一维数组
arr1 = np.array([1, 2, 3, 4])
print("一维数组:", arr1)
# 创建二维数组
arr2 = np.array([[1, 2], [3, 4]])
print("二维数组:\n", arr2)
# 创建三维数组
arr3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("三维数组:\n", arr3)
# 指定数据类型为浮点型
arr4 = np.array([1, 2, 3, 4], dtype=float)
print("指定浮点型数组:", arr4)
2. 数组形状操作 (reshape()
、flatten()
、ravel()
)
形状操作是将数组在不同维度之间转换的方式。对于多维数据处理,常常需要重新调整数组的形状来适应不同的操作或模型。
主要功能:
reshape():改变数组的形状而不改变其数据。注意,新形状必须与原数组的元素数量相匹配。 flatten():将多维数组展平成一维数组,返回的是数组的副本。 ravel():同样展平数组,但尽可能返回的是数组的视图而非副本,效率更高。
Python 实现
# 创建二维数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 改变形状为 (3, 2)
reshaped = arr.reshape((3, 2))
print("重塑后的数组:\n", reshaped)
# 展平数组
flattened = arr.flatten()
print("展平后的数组:", flattened)
# 使用 ravel 展平数组
ravelled = arr.ravel()
print("使用 ravel 展平的数组:", ravelled)
场景
这些形状操作在模型输入或预处理时很常用。例如,卷积神经网络的输入通常需要将图像从二维形式重塑为三维(width x height x channels
),而全连接层需要展平输入。
3. 数组索引与切片 (array slicing
)
索引和切片是数组操作的基础功能之一,它允许我们访问数组中的特定元素、子数组或进行修改操作。与 Python 的列表索引类似,但在 NumPy
中更强大,可以应用于多维数组。
主要功能:
单元素索引:通过下标访问数组中的某个元素。 切片:可以获取数组的子集,使用类似于 start:end:step
的切片方式。多维索引:在多维数组中,使用逗号分隔的索引来访问特定元素。
Python 实现
# 创建二维数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 访问单个元素
print("访问 (0, 1) 元素:", arr[0, 1])
# 切片操作
print("切片得到的子数组:\n", arr[1:, 1:])
# 使用步长进行切片
print("步长为 2 的切片:\n", arr[::2, ::2])
场景
在机器学习中,数据通常以矩阵或张量的形式存储和处理。索引和切片用于提取感兴趣的部分,如选取特征子集、批量数据等。
4. 数组广播 (broadcasting
)
广播是一种强大的机制,它允许 NumPy
以不同形状的数组参与操作。即使两个数组的维度不同,它们也能通过扩展较小数组的维度,使其形状与较大数组一致来进行运算。
主要功能:
形状自动匹配:可以让不同维度的数组进行算术操作, NumPy
会自动调整较小数组的形状。无需显式调整维度:无需手动使用 reshape()
,广播机制会自动处理。
Python 实现
# 广播标量和数组
arr = np.array([1, 2, 3])
print("数组与标量相加:", arr + 10)
# 广播不同形状的数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
arr3 = np.array([1, 2, 3])
print("二维数组与一维数组相加:\n", arr2 + arr3)
场景
广播广泛用于数组的批量操作,如在机器学习中可以快速处理特征归一化、矩阵加减法等。它减少了手动调整数组形状的需求,提高了代码简洁性和可读性。
5. 数学运算 (array operations
)
NumPy
提供了丰富的数学运算功能,这些运算以向量化的方式进行,能够在数组上快速执行各种数学计算,而无需使用显式的循环。
主要功能:
基本运算:加减乘除、指数运算等,直接在数组上操作。 统计运算:如 sum()
、mean()
、max()
、min()
等聚合函数。线性代数:如矩阵乘法( dot()
)、矩阵逆、特征值计算等。
Python 实现
arr = np.array([1, 2, 3])
# 基本算术运算
print("数组加 5:", arr + 5)
print("数组乘 2:", arr * 2)
# 数组的统计运算
print("数组的和:", arr.sum())
print("数组的均值:", arr.mean())
# 线性代数运算
mat1 = np.array([[1, 2], [3, 4]])
mat2 = np.array([[5, 6], [7, 8]])
print("矩阵乘法:\n", np.dot(mat1, mat2))
场景
在机器学习中,数学运算和统计函数广泛用于数据的归一化、标准化、特征处理等操作。而线性代数操作在模型计算(如梯度计算、矩阵乘法)中尤为重要。
6. 数组条件筛选 (boolean masking
)
布尔掩码(boolean masking
)是一种非常强大的数据筛选方式,它允许基于条件筛选数组中的元素。通过创建布尔数组或条件表达式,可以选取满足条件的元素。
主要功能:
布尔索引:根据条件表达式创建布尔数组,并用它来过滤原数组中的元素。 条件替换:使用 np.where()
根据条件选择性地替换数组中的值。
Python 实现
arr = np.array([1, 2, 3, 4, 5, 6])
# 布尔掩码筛选
mask = arr > 3
print("大于 3 的元素:", arr[mask])
# 使用 np.where 条件替换
new_arr = np.where(arr > 3, arr * 10, arr)
print("大于 3 的元素乘以 10:", new_arr)
场景
布尔掩码广泛用于数据预处理、异常值检测和特征工程。例如,你可以根据某个条件筛选数据集中的样本或特征,或基于条件对数据进行变换。
7. 数组合并与分割 (concatenate()
、split()
)
数组合并与分割是在处理多组数据时的常用操作,NumPy
提供了多个函数来处理这一需求。
主要功能:
concatenate():将多个数组沿指定轴拼接。 stack():沿新的维度进行堆叠,创建高维数组。 split():将一个数组拆分为多个子数组。
Python 实现
# 合并数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
combined = np.concatenate((arr1, arr2))
print("合并后的数组:", combined)
# 堆叠数组
stacked = np.stack((arr1, arr2), axis=0)
print("堆叠后的数组:\n", stacked)
# 分割数组
split_arr = np.split(combined, 2)
print("分割后的数组:", split_arr)
场景
合并和分割常用于数据增强、特征组合、模型输入预处理等场景。例如,你可以将多个特征列组合成一个矩阵,或者将大批量数据分割成多个小批次。
8. 数组维度扩展与压缩 (expand_dims()
、squeeze()
)
维度扩展与压缩用于在需要时增加或减少数组的维度。例如,在深度学习中,有时需要在批次维度、通道维度等位置扩展或压缩维度,以便适应模型输入的要求。
主要功能:
expand_dims():在指定轴插入一个新的维度,增加数组的维度。 squeeze():删除数组中尺寸为 1 的维度,压缩维度。
Python 实现
# 原始数组
arr = np.array([1, 2, 3])
# 扩展维度
expanded = np.expand_dims(arr, axis=0)
print("扩展维度后的数组:\n", expanded)
# 压缩维度
squeezed = np.squeeze(expanded)
print("压缩维度后的数组:", squeezed)
场景
维度扩展和压缩在图像处理、深度学习模型输入中很常见。例如,在卷积神经网络中,可能需要在输入数据的前面或后面增加一个批量维度或通道维度。
9. 数组排序与去重 (sort()
、unique()
)
数组排序与去重操作在数据处理中非常常见,尤其是在需要对特征进行排序或筛选唯一值时。
主要功能:
sort():对数组进行排序,默认按升序排序,可以指定轴。 unique():返回数组中的唯一值,并可以选择返回唯一值的索引和计数。
Python 实现
arr = np.array([3, 1, 2, 3, 4])
# 排序
sorted_arr = np.sort(arr)
print("排序后的数组:", sorted_arr)
# 去重
unique_arr = np.unique(arr)
print("去重后的数组:", unique_arr)
场景
排序和去重在特征工程和数据预处理中很常用,例如对类别特征进行唯一化处理或对数值特征进行排序操作。
10. 随机数生成 (np.random
模块)
随机数生成器允许我们生成符合特定分布的随机数组,这在机器学习、数据增强和蒙特卡洛方法中非常有用。
主要功能:
rand():生成均匀分布的随机数。 randn():生成标准正态分布的随机数。 randint():生成随机整数。 shuffle():对数组进行随机打乱。
Python 实现
# 生成均匀分布的随机数
rand_arr = np.random.rand(3, 3)
print("均匀分布的随机数数组:\n", rand_arr)
# 生成标准正态分布的随机数
randn_arr = np.random.randn(3, 3)
print("标准正态分布的随机数数组:\n", randn_arr)
# 生成随机整数
randint_arr = np.random.randint(0, 10, size=(3, 3))
print("随机整数数组:\n", randint_arr)
# 随机打乱数组
arr = np.array([1, 2, 3, 4, 5])
np.random.shuffle(arr)
print("打乱后的数组:", arr)
场景
在机器学习中,随机数生成广泛应用于初始化模型权重、生成数据集的随机批次以及进行数据增强(如随机裁剪、翻转等)。
下面,咱们举一个案例,整体的运用一下~
完整案例
案例中,加入数据生成、处理和可视化中引入 NumPy
操作,包括:
数据标准化、均值调整 形状变换 合并多个数组 使用条件筛选和广播操作 统计汇总
完整代码:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# 设置随机种子,确保结果可复现
np.random.seed(42)
# 1. 使用 NumPy 生成虚拟数据集
# 生成 X 特征数据,均匀分布在 0 到 10 之间
X = np.random.rand(100, 1) * 10
# 生成 Y 特征数据,假设 Y 与 X 存在线性关系,但有噪声影响
# Y = 2.5 * X + 噪声,噪声服从正态分布
noise = np.random.randn(100, 1) * 5
Y = 2.5 * X + noise
# 2. 数组操作 - 数据标准化 (Z-Score Normalization)
X_mean = X.mean()
X_std = X.std()
X_norm = (X - X_mean) / X_std # 标准化后的 X
Y_mean = Y.mean()
Y_std = Y.std()
Y_norm = (Y - Y_mean) / Y_std # 标准化后的 Y
# 3. 数组合并 - 合并标准化后的 X 和 Y
data = np.concatenate((X_norm, Y_norm), axis=1)
# 4. 数组形状变换
# 假设我们需要将一维数组展平处理或者重塑为不同形状
X_flat = X_norm.flatten() # 展平
Y_flat = Y_norm.flatten()
# 5. 条件筛选 - 筛选 X_norm 中大于 0 的数据
X_positive = X_norm[X_norm > 0]
Y_positive = Y_norm[:X_positive.shape[0]] # 对应筛选出的 Y 数据
# 6. 统计运算 - 计算均值、方差、最大值、最小值
X_stats = {
'mean': np.mean(X),
'var': np.var(X),
'max': np.max(X),
'min': np.min(X)
}
Y_stats = {
'mean': np.mean(Y),
'var': np.var(Y),
'max': np.max(Y),
'min': np.min(Y)
}
# 7. 广播操作 - 对 Y 进行批量运算,将所有元素乘以一个常数
Y_scaled = Y_norm * 2.5
# 8. 线性回归拟合 - 使用标准化后的数据
model = LinearRegression()
model.fit(X_norm, Y_norm)
Y_pred = model.predict(X_norm)
# 设置图形大小
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
fig.suptitle('Advanced Data Analysis: Scatter Plot, Regression Line, Distribution and Operations', fontsize=16)
# 绘制散点图和线性回归线
axs[0, 0].scatter(X_norm, Y_norm, color='red', label='Data Points (Normalized)', alpha=0.7)
axs[0, 0].plot(X_norm, Y_pred, color='blue', label='Regression Line', linewidth=2)
axs[0, 0].set_title('Normalized Scatter Plot with Regression Line')
axs[0, 0].set_xlabel('X (Normalized)')
axs[0, 0].set_ylabel('Y (Normalized)')
axs[0, 0].legend()
# 绘制 X 的直方图
axs[0, 1].hist(X_norm, bins=20, color='green', edgecolor='black', alpha=0.7)
axs[0, 1].set_title('Distribution of X (Normalized)')
axs[0, 1].set_xlabel('X Values')
axs[0, 1].set_ylabel('Frequency')
# 绘制 Y 的直方图
axs[1, 0].hist(Y_norm, bins=20, color='purple', edgecolor='black', alpha=0.7)
axs[1, 0].set_title('Distribution of Y (Normalized)')
axs[1, 0].set_xlabel('Y Values')
axs[1, 0].set_ylabel('Frequency')
# 绘制残差图,展示真实值与预测值之间的差异
residuals = Y_norm - Y_pred
axs[1, 1].scatter(X_norm, residuals, color='orange', label='Residuals', alpha=0.7)
axs[1, 1].axhline(0, color='black', linestyle='--', linewidth=2)
axs[1, 1].set_title('Residuals Plot (Normalized)')
axs[1, 1].set_xlabel('X (Normalized)')
axs[1, 1].set_ylabel('Residuals')
axs[1, 1].legend()
# 调整布局以避免子图重叠
plt.tight_layout(rect=[0, 0, 1, 0.96])
# 展示图形
plt.show()
# 打印统计信息
print("X 的统计信息:", X_stats)
print("Y 的统计信息:", Y_stats)
1. 数据标准化 (Z-Score Normalization
):
我们计算了 X
和Y
的均值和标准差,并将它们标准化为均值为 0,标准差为 1 的分布。这在数据分析和机器学习中非常常见,尤其是当特征具有不同量纲时,标准化可以提高模型的表现。
X_norm = (X - X_mean) / X_std
Y_norm = (Y - Y_mean) / Y_std
2. 数组合并 (concatenate
):
将标准化后的 X_norm
和Y_norm
合并为一个二维数组,以便于后续处理和分析。
data = np.concatenate((X_norm, Y_norm), axis=1)
3. 数组展平 (flatten
):
使用 flatten()
将标准化后的X_norm
和Y_norm
变为一维数组,以便在某些情况下需要将多维数组展平为一维时处理。
X_flat = X_norm.flatten()
Y_flat = Y_norm.flatten()
4. 条件筛选 (boolean masking
):
筛选 X_norm
中大于 0 的数据,并提取相应的Y_norm
值。条件筛选有助于对特定子集进行分析。
X_positive = X_norm[X_norm > 0]
Y_positive = Y_norm[:X_positive.shape[0]]
5. 统计运算:
计算了 X
和Y
的均值、方差、最大值和最小值。这些汇总信息有助于理解数据的分布情况。
X_stats = {
'mean': np.mean(X),
'var': np.var(X),
'max': np.max(X),
'min': np.min(X)
}
6. 广播操作 (broadcasting
):
对 Y_norm
使用广播操作,将其所有元素乘以常数 2.5,演示如何对数组进行批量操作。
Y_scaled = Y_norm * 2.5
散点图与回归线:展示了标准化后的 X
和Y
的散点图,并绘制了回归线,直观展示特征间的线性关系。X 和 Y 的分布直方图:展示了标准化后的数据分布。标准化将数据的均值调整为 0,标准差调整为 1,因此数据更加集中。 残差图:残差图展示了回归模型的误差,帮助评估模型的拟合效果。
往期 Numpy 合集
最后