Skip to content

数据准备

使用 Python 进行机器学习 - 数据准备

Section titled “使用 Python 进行机器学习 - 数据准备”

数据是机器学习算法的燃料。然而,从现实世界收集的原始数据通常是杂乱、不一致和不完整的。直接将此类数据输入到机器学习模型中通常会导致性能不佳或错误。因此,数据准备(也称为数据预处理或数据清洗)是机器学习工作流程中一个关键且通常耗时的步骤。

数据准备涉及将原始数据转换为干净、结构良好、适合机器学习算法的格式。这确保了数据具有正确的尺度、格式以及对特定问题有意义的特征。

预处理是必要的,因为:

  • 不一致的尺度: 特征通常具有不同的单位和范围(例如,年龄以年为单位,收入以美元为单位)。许多算法(如 SVM、k-NN、基于梯度下降的方法)如果特征尺度差异很大,性能会变差或收敛缓慢。
  • 算法要求: 一些算法对数据格式有特定要求(例如,只接受数值输入、标准化数据)。
  • 缺失值: 现实世界的数据经常包含缺失项,大多数算法无法直接处理。
  • 分类数据: 算法通常需要数值输入,因此分类特征(如“颜色”或“国家”)需要编码。
  • 不相关或冗余特征: 一些特征可能不会提供有用信息,或者与其他特征高度相关,可能导致模型性能下降。
  • 异常值: 极端值可能对某些模型产生不成比例的影响。
  • 数据质量: 解决数据中的错误、不一致性和噪声。

让我们使用 Python 的 Scikit-learn 库探索关键的预处理技术。

关键的第一步。常见的策略包括:

  • 删除: 删除包含缺失值的行(样本)或列(特征)。简单,但可能导致显著的数据损失。
  • 插补 (Imputation): 用估计的替代值填充缺失值。常用方法:
    • 均值/中位数/众数插补: 用特征的均值或中位数替换缺失的数值,用众数替换缺失的分类值。使用 sklearn.impute.SimpleImputer。
    • 更高级的方法: 回归插补、k-NN 插补或使用模型预测缺失值可能更准确,但也更复杂。

(此处省略了插补的代码示例以保持简洁,但在实践中至关重要。请参考 Scikit-learn 文档获取 SimpleImputer 的详细信息。)

调整特征的尺度对于许多算法至关重要。

a) 缩放 (Scaling)(归一化到 [0, 1])

Section titled “a) 缩放 (Scaling)(归一化到 [0, 1])”

将特征重新缩放到一个固定范围,通常是 [0, 1] 或 [-1, 1]。当数据分布不一定是高斯分布或算法期望输入在有界范围内时非常有用。

使用 sklearn.preprocessing.MinMaxScaler。

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
# Load data (replace path)
# 加载数据(替换路径)
path = 'pima-indians-diabetes.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pd.read_csv(path, names=names)
# Separate features (X) and target (y) - good practice
# 分离特征 (X) 和目标变量 (y) - 良好实践
array = dataframe.values
X = array[:, :-1] # Features
# 特征
y = array[:, -1] # Target
# 目标变量
# Initialize the scaler
# 初始化缩放器
scaler = MinMaxScaler(feature_range=(0, 1))
# Fit the scaler to the features and transform the data
# IMPORTANT: Fit ONLY on training data in a real scenario, then transform train and test sets
# 将缩放器拟合到特征并转换数据
# 重要:在实际场景中,仅对训练数据进行拟合,然后对训练集和测试集进行转换
X_scaled = scaler.fit_transform(X)
# Summarize scaled data
# 总结缩放后的数据
np.set_printoptions(precision=2) # Set print precision
# 设置打印精度
print("Scaled data (first 5 rows):\n", X_scaled[0:5])
# 缩放后的数据(前 5 行)

b) 标准化 (Standardization)(Z-score 归一化)

Section titled “b) 标准化 (Standardization)(Z-score 归一化)”

将特征转换为均值为零 (μ=0)、方差为一 (σ=1) 的分布。它将数据中心化。这通常适用于假设高斯分布或对特征方差敏感的算法(如 PCA、逻辑回归、SVM 等)。

使用 sklearn.preprocessing.StandardScaler。

import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
# Load data (replace path)
# 加载数据(替换路径)
path = 'pima-indians-diabetes.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pd.read_csv(path, names=names)
# Separate features (X) and target (y)
# 分离特征 (X) 和目标变量 (y)
array = dataframe.values
X = array[:, :-1]
y = array[:, -1]
# Initialize the scaler
# 初始化缩放器
scaler = StandardScaler()
# Fit the scaler to the features and transform the data
# IMPORTANT: Fit ONLY on training data in a real scenario
# 将缩放器拟合到特征并转换数据
# 重要:在实际场景中,仅对训练数据进行拟合
X_standardized = scaler.fit_transform(X)
# Summarize standardized data
# 总结标准化后的数据
np.set_printoptions(precision=2)
print("Standardized data (first 5 rows):\n", X_standardized[0:5])
# 标准化后的数据(前 5 行)

注意: 还存在其他缩放器,如 RobustScaler,它们对异常值不那么敏感。

3. 规范化 (Normalization)(样本维度)

Section titled “3. 规范化 (Normalization)(样本维度)”

规范化是独立地重新调整每个样本(行)的尺度,使其具有单位范数(长度为 1)。这与按列操作的特征缩放不同。它常用于文本分类或聚类,此时样本的幅度不如其方向或相对比例重要。

类型:L1(绝对值之和为 1)和 L2(平方和为 1,即欧几里得范数)。

使用 sklearn.preprocessing.Normalizer。

import pandas as pd
import numpy as np
from sklearn.preprocessing import Normalizer
# Load data (replace path)
# 加载数据(替换路径)
path = 'pima-indians-diabetes.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pd.read_csv(path, names=names)
# Separate features (X)
# 分离特征 (X)
array = dataframe.values
X = array[:, :-1]
# Initialize the normalizer (L2 norm by default)
# 初始化规范化器(默认为 L2 范数)
normalizer = Normalizer(norm='l2') # Or norm='l1'
# 或 norm='l1'
# Fit (not strictly necessary for Normalizer) and transform
# 拟合(对于 Normalizer 并非严格必要)并转换
X_normalized = normalizer.fit_transform(X)
# Summarize normalized data
# 总结规范化后的数据
np.set_printoptions(precision=2)
print("L2 Normalized data (first 5 rows):\n", X_normalized[0:5])
# L2 规范化后的数据(前 5 行)

根据指定的阈值将数值特征转换为二进制(0 或 1)值。对于创建二进制标志或处理您想使其更清晰的概率非常有用。

使用 sklearn.preprocessing.Binarizer。

import pandas as pd
import numpy as np
from sklearn.preprocessing import Binarizer
# Load data (replace path)
# 加载数据(替换路径)
path = 'pima-indians-diabetes.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pd.read_csv(path, names=names)
# Separate features (X)
# 分离特征 (X)
array = dataframe.values
X = array[:, :-1]
# Initialize the binarizer with a threshold (e.g., 0.0, adjust as needed)
# 使用阈值初始化二值化器(例如 0.0,根据需要调整)
binarizer = Binarizer(threshold=0.0)
# Fit (not necessary) and transform
# 拟合(非必要)并转换
X_binarized = binarizer.fit_transform(X)
# Summarize binarized data
# 总结二值化后的数据
np.set_printoptions(precision=2)
print("Binarized data (threshold=0.0, first 5 rows):\n", X_binarized[0:5])
# 二值化后的数据(阈值=0.0,前 5 行)

5. 编码分类特征 (Encoding Categorical Features)

Section titled “5. 编码分类特征 (Encoding Categorical Features)”

机器学习算法需要数值输入。分类特征(文本标签)必须进行转换。

为每个类别分配一个唯一的整数。示例:[‘red’, ‘green’, ‘blue’] -> [0, 1, 2]。

用例: 主要适用于对分类任务中的目标变量 (y) 进行编码。

注意: 如果类别之间没有固有的顺序关系,避免对输入特征 (X) 使用标签编码,因为它会引入人为的序数关系(例如,暗示绿色“大于”红色)。

使用 sklearn.preprocessing.LabelEncoder。

示例(标签编码 - 适用于目标变量)
Section titled “示例(标签编码 - 适用于目标变量)”
import numpy as np
from sklearn.preprocessing import LabelEncoder
# Sample target variable labels
# 样本目标变量标签
labels = np.array(['cat', 'dog', 'cat', 'fish', 'dog'])
print("Original labels:", labels)
# 原始标签
# Initialize encoder
# 初始化编码器
encoder = LabelEncoder()
# Fit and transform
# 拟合并转换
encoded_labels = encoder.fit_transform(labels)
print("Encoded labels:", encoded_labels)
# 编码后的标签
# See the mapping
# 查看映射
print("Mapping (Classes to Encoded Values):", dict(zip(encoder.classes_, encoder.transform(encoder.classes_))))
# 映射(类别到编码值)
# Inverse transform (get original labels back)
# 逆转换(恢复原始标签)
decoded_labels = encoder.inverse_transform(encoded_labels)
print("Decoded labels:", decoded_labels)
# 解码后的标签

为每个类别创建一个新的二进制(0 或 1)特征。示例:具有 [‘red’, ‘green’, ‘blue’] 的 ‘color’ 特征变为三个特征:‘color_red’, ‘color_green’, ‘color_blue’。原始值为 ‘red’ 的样本会变成 [1, 0, 0]。

用例: 对名义分类输入特征 (X)(类别没有顺序)进行编码的标准方法。

使用 sklearn.preprocessing.OneHotEncoder(更灵活)或 pandas.get_dummies(对于 DataFrame 通常更简单)。

示例(独热编码 - 适用于输入特征)
Section titled “示例(独热编码 - 适用于输入特征)”
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
# Sample DataFrame with a categorical feature
# 包含分类特征的样本 DataFrame
data = pd.DataFrame({'color': ['red', 'green', 'blue', 'red'], 'size': ['M', 'L', 'S', 'M']})
print("Original DataFrame:\n", data)
# 原始 DataFrame
# Using pandas.get_dummies (simple)
# 使用 pandas.get_dummies(简单)
data_encoded_pd = pd.get_dummies(data, columns=['color', 'size'], drop_first=False) # drop_first=True avoids multicollinearity if needed
# 如果需要,drop_first=True 可以避免多重共线性问题
print("\nEncoded using pandas.get_dummies:\n", data_encoded_pd)
# 使用 pandas.get_dummies 编码后的数据
# Using sklearn.preprocessing.OneHotEncoder (more control, integrates with Pipelines)
# 使用 sklearn.preprocessing.OneHotEncoder(更多控制,可与 Pipelines 集成)
encoder_ohe = OneHotEncoder(sparse_output=False) # sparse=False returns a dense array
# sparse_output=False 返回密集数组
# Fit and transform (select categorical columns first)
# 拟合并转换(先选择分类列)
categorical_cols = ['color', 'size']
encoded_array = encoder_ohe.fit_transform(data[categorical_cols])
# Get feature names for the new columns
# 获取新列的特征名称
feature_names = encoder_ohe.get_feature_names_out(categorical_cols)
# Create a new DataFrame with encoded features
# 创建一个包含编码后特征的新 DataFrame
data_encoded_sklearn = pd.DataFrame(encoded_array, columns=feature_names, index=data.index)
print("\nEncoded using sklearn.OneHotEncoder:\n", data_encoded_sklearn)
# 使用 sklearn.OneHotEncoder 编码后的数据
# You would typically concatenate this back with numerical features if any
# 通常会将其与数值特征(如果有的话)拼接回来

数据准备是机器学习中的一项基础技能。使用的具体技术取决于数据和选择的算法。有条不紊地应用这些步骤可以确保您的模型接收到最有效格式的数据,从而获得更好的性能和更可靠的结果。请记住,对训练数据和测试数据一致地应用预处理步骤,最好使用 Scikit-learn Pipelines 来防止数据泄露。

更多资源: