数据预处理是数据分析、机器学习和深度学习等领域中的重要步骤。它包括清洗、转换、归一化、编码等操作,旨在使数据适合于建模和分析。数据预处理的质量直接影响模型的性能和准确性。下面详细介绍数据预处理的常见步骤和技术。
1. 数据清洗:
- 处理缺失值:
- 删除缺失数据: 如果缺失值的数量较少,或者缺失的样本对分析无关紧要,可以直接删除。
- 插值填补: 使用均值、中位数、众数、或插值等方法填补缺失值。
import pandas as pd # 删除包含缺失值的行 df.dropna(inplace=True) # 用均值填补缺失值 df.fillna(df.mean(), inplace=True)- 预测填补: 使用其他变量预测缺失值,例如使用回归模型填补。
你可以使用回归模型来填补缺失值。以下是使用scikit-learn中的回归模型来填补缺失值的代码示例。假设我们有一个数据集,其中某一列有缺失值,其他列将用于预测该列的缺失值。
步骤
- 数据准备:我们会将数据分为两部分——缺失值部分和非缺失值部分。
- 训练模型:在非缺失值部分使用回归模型来训练。
- 预测缺失值:使用模型对缺失值部分进行预测。
以下是代码示例:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.impute import SimpleImputer
# 示例数据集
data = {
'feature1': [1, 2, 3, 4, 5],
'feature2': [2, 4, np.nan, 8, 10],
'target': [5, 10, 15, np.nan, 25]
}
df = pd.DataFrame(data)
# 1. 将有缺失值的部分和没有缺失值的部分分开
# 找到 target 列中没有缺失值的行
df_no_missing = df[df['target'].notna()]
df_missing = df[df['target'].isna()]
# 2. 使用 feature1 和 feature2 作为预测特征,target 作为标签
X_train = df_no_missing[['feature1', 'feature2']]
y_train = df_no_missing['target']
# 填补 feature2 中的缺失值(假设 feature2 中也有缺失值)
imputer = SimpleImputer(strategy='mean')
X_train = imputer.fit_transform(X_train)
# 3. 使用回归模型进行训练
regressor = LinearRegression()
regressor.fit(X_train, y_train)
# 4. 对缺失值部分进行预测
X_missing = df_missing[['feature1', 'feature2']]
X_missing = imputer.transform(X_missing)
df_missing['target'] = regressor.predict(X_missing)
# 5. 填补原始数据中的缺失值
df.loc[df['target'].isna(), 'target'] = df_missing['target']
print(df)
-
处理异常值:
- 检测异常值: 可以使用箱线图、标准差、Z-score 等方法检测异常值。
# 使用Z-score检测异常值 from scipy import stats z_scores = stats.zscore(df['column_name']) abs_z_scores = np.abs(z_scores) filtered_entries = (abs_z_scores < 3) df = df[filtered_entries]
使用箱线图检测异常值
你可以使用箱线图(Box Plot)来检测数据集中的异常值。箱线图通过展示数据的五数概括(最小值、第一四分位数、中位数、第三四分位数、最大值)来识别潜在的异常值。通常,超出 1.5 倍四分位距(IQR: Interquartile Range) 的数据点被视为异常值。
以下是如何使用 matplotlib 和 seaborn 来绘制箱线图并检测异常值的代码示例。
步骤
- 计算 IQR:第一四分位数(Q1)和第三四分位数(Q3)的差值。
- 定义上下限:用 Q1 - 1.5 * IQR 和 Q3 + 1.5 * IQR 作为异常值检测的标准。
- 绘制箱线图:使用
seaborn库绘制。
代码示例
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 示例数据集
data = {
'feature1': [10, 12, 14, 15, 16, 18, 22, 25, 30, 100], # 100 是异常值
'feature2': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
df = pd.DataFrame(data)
# 绘制箱线图
plt.figure(figsize=(8, 6))
sns.boxplot(data=df['feature1'])
plt.title("Box Plot for Feature1")
plt.show()
# 计算 IQR 进行异常值检测
Q1 = df['feature1'].quantile(0.25)
Q3 = df['feature1'].quantile(0.75)
IQR = Q3 - Q1
# 定义异常值的上下限
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 找到异常值
outliers = df[(df['feature1'] < lower_bound) | (df['feature1'] > upper_bound)]
print("异常值为:")
print(outliers)
代码说明
- 箱线图:使用
seaborn.boxplot()来展示feature1列的箱线图。 - IQR 计算:通过
quantile()方法来计算 Q1 和 Q3。 - 异常值检测:通过计算上下限,筛选出异常值。
- 绘制图表:用
matplotlib显示箱线图。
输出结果
- 图表中,箱线图的 “胡须” 部分会标识正常范围的数据点,位于胡须之外的数据点被视为异常值(例如 100)。
- 控制台中会输出检测出的异常值。
使用标准差检测异常值
使用标准差来检测异常值是另一种常用的方法。通过计算数据的均值和标准差,可以定义一个数据范围,通常使用 3倍标准差 作为上下界。任何超出此范围的值都被视为异常值。
步骤
- 计算均值和标准差。
- 定义上下界:用
mean ± 3 * standard deviation作为异常值检测的标准。 - 检测异常值。
以下是如何使用 pandas 和 numpy 来基于标准差检测异常值的代码示例。
代码示例
import pandas as pd
import numpy as np
# 示例数据集
data = {
'feature1': [10, 12, 14, 15, 16, 18, 22, 25, 30, 100], # 100 是异常值
'feature2': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
df = pd.DataFrame(data)
# 计算均值和标准差
mean = df['feature1'].mean()
std_dev = df['feature1'].std()
# 定义异常值的上下界 (mean ± 3 * standard deviation)
lower_bound = mean - 3 * std_dev
upper_bound = mean + 3 * std_dev
# 找到异常值
outliers = df[(df['feature1'] < lower_bound) | (df['feature1'] > upper_bound)]
print("异常值为:")
print(outliers)
# 输出上下界
print(f"下界: {lower_bound}, 上界: {upper_bound}")
代码说明
- 均值和标准差计算:
mean()和std()函数用于计算feature1列的均值和标准差。 - 定义上下界:使用均值和 3 倍标准差来确定检测异常值的范围。
- 筛选异常值:通过条件筛选找到超出上下界的值。
输出结果
- 控制台中会输出检测出的异常值(例如
100)。 - 输出上下界的数值范围,用于进一步分析。
方法解释
- 3倍标准差法:对于符合正态分布的数据,大约 99.7% 的数据点应该在均值的 ±3 标准差范围内。因此,超出此范围的数据点被视为潜在的异常值。
- 适用性:该方法适用于正态分布或近似正态分布的数据。如果数据的分布偏离正态分布,则应谨慎使用此方法。
处理异常值: 异常值可以被删除、替换或者转换。可以使用插值法来平滑异常值。
插值法是一种通过已知数据点之间的插值来平滑数据的方法,能够很好地处理异常值。常用的插值方法包括线性插值、样条插值等。对于异常值,可以通过替换为插值值来实现平滑。
以下是如何使用 pandas 提供的插值功能来平滑异常值的步骤:
步骤
- 识别异常值:先通过某种方法(如标准差法或箱线图)检测到异常值。
- 使用插值法:利用
pandas中的interpolate()函数平滑异常值。 - 替换异常值:将异常值替换为插值后的值。
代码示例
import pandas as pd
import numpy as np
# 示例数据集
data = {
'feature1': [10, 12, 14, 15, 16, 18, 22, 25, 30, 100], # 100 是异常值
'feature2': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
df = pd.DataFrame(data)
# 使用标准差法检测异常值
mean = df['feature1'].mean()
std_dev = df['feature1'].std()
lower_bound = mean - 3 * std_dev
upper_bound = mean + 3 * std_dev
# 找到异常值位置
outliers = (df['feature1'] < lower_bound) | (df['feature1'] > upper_bound)
# 将异常值替换为 NaN
df.loc[outliers, 'feature1'] = np.nan
# 使用线性插值平滑数据
df['feature1'] = df['feature1'].interpolate(method='linear')
# 查看结果
print("插值后数据:")
print(df)
代码说明
- 检测异常值:通过标准差法识别异常值,找到异常值所在的位置。
- 替换为 NaN:将检测到的异常值替换为
NaN,为后续插值做准备。 - 线性插值:使用
pandas的interpolate()函数对NaN位置进行线性插值,平滑异常值。 - 输出结果:异常值(如
100)将被替换为插值后的值。
插值方法说明
- 线性插值:基于两个相邻点之间的直线关系插入值,适用于简单数据。
- 其他插值方法:你也可以使用
polynomial,spline, 或nearest等插值方法。- 示例:
df['feature1'].interpolate(method='polynomial', order=2)可以进行二次多项式插值。
- 示例:
优势
- 插值法可以在保持数据趋势的情况下,平滑掉异常值,避免直接删除数据点带来的数据损失。
- 适用于时序数据或连续数据,能够补充缺失值或异常值。
2. 数据转换:
-
标准化(Standardization):
- 将特征值转换为均值为0、方差为1的标准正态分布。常用于模型对数据尺度敏感的情况(如线性回归、逻辑回归、SVM)。
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() df_scaled = scaler.fit_transform(df) -
归一化(Normalization):
- 将特征值缩放到指定范围内(通常是 [0, 1])。适用于范围差异较大的数据,如深度学习中的输入数据。
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() df_normalized = scaler.fit_transform(df) -
对数变换(Log Transformation):
- 将数据转换为对数形式,通常用于处理数据的偏态分布或减少异方差性。
import numpy as np df['log_column'] = np.log(df['column_name'] + 1) # +1防止log(0) -
分箱(Binning):
- 将连续变量转换为离散变量,可以使用等宽分箱或等频分箱。
df['binned_column'] = pd.cut(df['column_name'], bins=5) -
One-Hot编码:
- 将分类变量转换为二进制向量,适用于机器学习算法需要数值输入的场景。
df = pd.get_dummies(df, columns=['categorical_column']) -
标签编码(Label Encoding):
- 将分类变量转换为整数值,每个类别对应一个整数。适用于树模型等不需要特征标准化的算法。
from sklearn.preprocessing import LabelEncoder le = LabelEncoder() df['encoded_column'] = le.fit_transform(df['categorical_column'])
3. 特征选择:
-
过滤法(Filter Method):
- 使用统计方法(如方差、卡方检验、相关系数)选择特征,剔除冗余或不相关的特征。
from sklearn.feature_selection import SelectKBest, chi2 X_new = SelectKBest(chi2, k=10).fit_transform(X, y) -
嵌入法(Embedded Method):
- 基于模型的特征选择,例如 L1 正则化(Lasso)、决策树的特征重要性。
from sklearn.linear_model import Lasso lasso = Lasso(alpha=0.01) lasso.fit(X, y) model = SelectFromModel(lasso, prefit=True) X_new = model.transform(X) -
包裹法(Wrapper Method):
- 使用递归特征消除(RFE)或其他算法通过不断地训练模型来选择特征。
from sklearn.feature_selection import RFE from sklearn.linear_model import LogisticRegression model = LogisticRegression() rfe = RFE(model, 10) X_new = rfe.fit_transform(X, y)
4. 特征工程:
-
特征交互:
- 创建特征的组合,生成新的特征。例如,将两个特征相乘或相除。
df['new_feature'] = df['feature1'] * df['feature2'] -
多项式特征:
- 生成特征的多项式项,用于线性模型中提升表现。
from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2) X_poly = poly.fit_transform(X) -
时间特征提取:
- 从时间戳中提取出年、月、日、星期等信息。
df['year'] = df['date_column'].dt.year df['month'] = df['date_column'].dt.month df['day_of_week'] = df['date_column'].dt.dayofweek
5. 数据拆分:
-
训练集与测试集划分:
- 将数据集拆分为训练集和测试集,常用的划分比例是 70% / 30% 或 80% / 20%。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) -
交叉验证:
- 使用 K 折交叉验证评估模型性能,避免过拟合。
from sklearn.model_selection import cross_val_score scores = cross_val_score(model, X, y, cv=5)
6. 数据增强:
-
数据扩增:
- 对图像、文本等数据进行增强,生成新的样本,通常用于深度学习。
from keras.preprocessing.image import ImageDataGenerator datagen = ImageDataGenerator(rotation_range=40, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
总结:
数据预处理是模型构建过程中至关重要的一步。高质量的预处理能帮助模型更好地理解数据,从而提升模型性能。不同类型的数据和任务可能需要不同的预处理方法,因此在具体项目中应灵活应用这些技术。
1616

被折叠的 条评论
为什么被折叠?



