数据预处理
数据预处理
数据预处理是机器学习流程中至关重要的一步。高质量的数据预处理能够显著提升模型性能。本文将介绍数据清洗、缺失值处理、标准化和归一化等常用技术。
数据清洗
数据清洗是识别和纠正数据中错误、不一致和异常值的过程。常见的数据质量问题包括重复值、异常值和不一致的格式。
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.impute import SimpleImputer
# 创建示例数据
data = {
'年龄': [25, 30, 35, None, 45, 200, 30, 28],
'收入': [5000, 8000, 12000, 6000, None, 9000, 7500, 8000],
'城市': ['北京', '上海', '广州', '深圳', '北京', '上海', '广州', '深圳']
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
print(f"\n数据形状: {df.shape}")
print(f"重复行数: {df.duplicated().sum()}")
print(f"各列缺失值:\n{df.isnull().sum()}")
缺失值处理
缺失值处理是数据预处理的重要环节。常用的处理方法包括删除、填充和插值。
# 方法1: 删除含缺失值的行
df_dropped = df.dropna()
print("删除缺失值后:")
print(df_dropped)
# 方法2: 用均值填充数值列
df_mean = df.copy()
df_mean['年龄'] = df_mean['年龄'].fillna(df_mean['年龄'].mean())
df_mean['收入'] = df_mean['收入'].fillna(df_mean['收入'].mean())
print("\n均值填充后:")
print(df_mean)
# 方法3: 用中位数填充
df_median = df.copy()
df_median['年龄'] = df_median['年龄'].fillna(df_median['年龄'].median())
print("\n中位数填充后:")
print(df_median)
# 方法4: 使用sklearn的SimpleImputer
imputer = SimpleImputer(strategy='mean')
df_imputed = df.copy()
df_imputed['年龄', '收入'](/notes/-) = imputer.fit_transform(df['年龄', '收入'](/notes/-))
print("\nSimpleImputer填充后:")
print(df_imputed)
异常值检测与处理
异常值可能严重影响模型性能,需要识别并适当处理。
# 使用IQR方法检测异常值
def detect_outliers_iqr(df, column):
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]
return outliers, lower_bound, upper_bound
# 检测年龄列的异常值
outliers, lower, upper = detect_outliers_iqr(df, '年龄')
print(f"年龄列的异常值阈值: [{lower:.2f}, {upper:.2f}]")
print(f"异常值个数: {len(outliers)}")
# 处理异常值: 截断法
df_cleaned = df.copy()
df_cleaned['年龄'] = df_cleaned['年龄'].clip(lower=lower, upper=upper)
print("\n截断异常值后:")
print(df_cleaned)
数据标准化
标准化将数据转换为均值为0、标准差为1的分布,适用于基于距离的算法如KNN、SVM等。
# 创建数值数据
X = np.array([[25, 5000], [30, 8000], [35, 12000], [45, 15000], [28, 7000]])
# 方法1: Z-score标准化
scaler_standard = StandardScaler()
X_standard = scaler_standard.fit_transform(X)
print("Z-score标准化结果:")
print(X_standard)
print(f"均值: {X_standard.mean(axis=0)}")
print(f"标准差: {X_standard.std(axis=0)}")
# 方法2: 手动实现标准化
X_manual = (X - X.mean(axis=0)) / X.std(axis=0)
print("\n手动标准化结果:")
print(X_manual)
数据归一化
归一化将数据缩放到[0,1]区间,适用于神经网络和需要处理不同尺度特征的场景。
# Min-Max归一化
scaler_minmax = MinMaxScaler()
X_minmax = scaler_minmax.fit_transform(X)
print("Min-Max归一化结果:")
print(X_minmax)
print(f"最小值: {X_minmax.min(axis=0)}")
print(f"最大值: {X_minmax.max(axis=0)}")
# MaxAbs归一化(适用于稀疏数据)
from sklearn.preprocessing import MaxAbsScaler
scaler_maxabs = MaxAbsScaler()
X_maxabs = scaler_maxabs.fit_transform(X)
print("\nMaxAbs归一化结果:")
print(X_maxabs)
类别型数据编码
对于类别型特征,需要进行编码转换为数值形式。
# 标签编码
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df['城市编码'] = le.fit_transform(df['城市'])
print("标签编码结果:")
print(df['城市', '城市编码'](/notes/-))
# 独热编码
df_onehot = pd.get_dummies(df['城市'], prefix='城市')
print("\n独热编码结果:")
print(df_onehot)
# 使用sklearn的OneHotEncoder
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(sparse_output=False)
city_encoded = ohe.fit_transform(df['城市'](/notes/))
print("\nOneHotEncoder结果:")
print(city_encoded)
完整的数据预处理流水线
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
# 定义预处理流水线
numerical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
# 组合预处理器
preprocessor = ColumnTransformer(
transformers=[
('num', numerical_transformer, ['年龄', '收入']),
('cat', categorical_transformer, ['城市'])
])
# 应用预处理
X_processed = preprocessor.fit_transform(df)
print("预处理后的数据形状:", X_processed.shape)
print("预处理后的数据示例:")
print(X_processed[:3])
数据预处理是机器学习项目成功的基础。合理的预处理策略能够提升模型的准确性和稳定性,是每位数据科学家必须掌握的技能。