机器学习入门实战 5 - 特征工程
📌 特征工程实战——优化房价预测模型
🏡 背景故事
你是一名数据科学家,在一家房地产公司负责房价预测模型的优化。最近,团队发现:
- 数据维度过高(80+ 个特征),导致计算慢,模型复杂度高
- 线性回归效果一般,预测误差较大
- 如何提高模型的准确率,并降低计算成本?
你决定使用特征工程优化数据,让模型运行更快、更准!
你将尝试:
- 变量选择(SelectKBest) —— 选择最重要的
K
个特征 - PCA(主成分分析) —— 进一步去掉冗余信息,减少计算量
- 线性回归 vs. 随机森林 —— 选择最佳的预测模型
最终目标:提升房价预测的准确率,同时降低计算复杂度!
可以从Kaggle下载本文使用的 train.csv 数据集文件。
📌 1. 加载和检查数据
📌 安装所需工具
pip install pandas numpy seaborn matplotlib scikit-learn
📌 导入库
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
📌 加载数据
df = pd.read_csv("train.csv")
# 查看数据结构
print(df.shape) # (1460, 81) —— 有 80 个特征
print(df.head())
✅ 数据说明
SalePrice
:房价(目标变量)- 其他
80
列是影响房价的特征
📌 2. 数据预处理
🔹 2.1 处理缺失值
📌 为什么?
- 机器学习模型无法处理缺失值,必须进行填充。
- 数值型列:用中位数填充(避免极端值影响)。
- 类别型列:用**众数(最常见值)**填充(保持数据一致性)。
📌 检查缺失值
missing_values = df.isnull().sum()
missing_values = missing_values[missing_values > 0].sort_values(ascending=False)
print(missing_values)
📌 填充缺失值
# 填充数值列
df = df.fillna(df.select_dtypes(include=["number"]).median())
# 填充类别列
for col in df.select_dtypes(include=["object"]).columns:
df[col] = df[col].fillna(df[col].mode()[0])
🔹 2.2 处理类别变量
📌 为什么?
- 类别变量(Categorical Variables) 是
object
类型的数据,例如:Neighborhood
(街区)HouseStyle
(房屋风格)
- 问题:机器学习模型无法直接处理文本类型的特征!
- 解决方案:使用独热编码(One-Hot Encoding)
📌 代码
df = pd.get_dummies(df, drop_first=True)
📌 为什么使用 drop_first=True
?
- 避免多重共线性(Dummy Variable Trap),减少冗余信息。
📌 3. 归一化(标准化)
📌 为什么?
- 不同特征的取值范围不同,如果不标准化,PCA 可能会只关注大数值特征(如
LotArea
),导致降维失效。
📌 使用 StandardScaler()
进行标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X = df.drop(columns=["SalePrice"])
X_scaled = scaler.fit_transform(X)
✅ 标准化后,每个特征的均值变为 0,标准差变为 1。
📌 4. 变量选择(SelectKBest)
📌 为什么?
- 高维数据中,很多特征可能无关紧要,直接删除不重要的特征可以提高模型效率。
SelectKBest
通过**统计方法(F检验)**选出最重要的K
个特征。
📌 代码
selector = SelectKBest(score_func=f_regression, k=50) # 选择 50 个最重要的特征
X_selected = selector.fit_transform(X_scaled, df["SalePrice"])
📌 5. PCA 降维
📌 为什么?
- 即使
SelectKBest
选了 50 个特征,仍然可能存在冗余信息(多个特征可能携带相似信息)。 - **PCA(主成分分析)**可以进一步去掉不必要的信息,减少计算量,提高模型效率。
📌 代码
pca = PCA(n_components=0.95) # 保留 95% 信息
X_pca = pca.fit_transform(X_selected)
✅ PCA 将会自动选择 n_components,保证尽可能少的特征保留 95% 以上的信息。
📌 绘制 PCA 贡献率曲线
cumulative_variance = np.cumsum(pca.explained_variance_ratio_)
plt.figure(figsize=(8,5))
plt.plot(range(1, len(cumulative_variance) + 1), cumulative_variance, marker="o", linestyle="--")
plt.axhline(y=0.95, color="r", linestyle="--") # 添加 95% 参考线
plt.xlabel("主成分数量")
plt.ylabel("累计解释方差")
plt.title("PCA 贡献率曲线")
plt.show()
📌 6. 训练房价预测模型
📌 拆分训练集 & 测试集
X_train, X_test, y_train, y_test = train_test_split(X_pca, df["SalePrice"], test_size=0.2, random_state=42)
📌 模型 1:线性回归
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
print(f"线性回归 MAE:{mae:.2f}")
📌 模型 2:随机森林
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)
mae_rf = mean_absolute_error(y_test, y_pred_rf)
print(f"随机森林 MAE:{mae_rf:.2f}")
📌 7. 结果分析
方法 | 作用 | MAE 误差 |
---|---|---|
线性回归 | 适用于简单线性数据 | 20,445.97 |
随机森林 | 适用于非线性数据,处理复杂关系 | 19,937.12 |
📌 结论
- PCA 降维后,随机森林的误差低于线性回归,说明房价预测可能是非线性问题。
📌 小结
🔹 1. 什么是特征工程?
特征工程是将原始数据转换为更有利于机器学习的特征的过程。
好特征 = 更高的模型准确率 + 更少的计算资源。
主要步骤:
- 数据清理(处理缺失值、异常值)
- 类别变量转换(One-Hot 编码、Label 编码)
- 归一化与标准化(确保不同尺度的特征影响均衡)
- 特征选择(去掉冗余特征,提高模型效率)
- 特征降维(PCA、LDA 等,减少计算成本)
🔹 2. 本文做了哪些特征工程?
步骤 | 方法 | 代码 |
---|---|---|
处理缺失值 | 用中位数填充数值列,用众数填充类别列 | df.fillna(df.median()) |
类别变量转换 | One-Hot 编码(去掉多重共线性) | df = pd.get_dummies(df, drop_first=True) |
标准化 | 让所有特征具有相同尺度 | StandardScaler() |
特征选择 | 选择最相关的 K 个特征 | SelectKBest(k=50) |
PCA 降维 | 进一步减少冗余信息 | PCA(n_components=0.95) |