train_pred = {} test_pred = {} # 将NaN值用中位数填充 X_train = X_train.fillna(X_train.median()) X_test = X_test.fillna(X_train.median()) oof = np.zeros(X_train.shape[0]) prediction = np.zeros(X_test.shape[0]) fold = 5 skf = StratifiedKFold(n_splits=fold, random_state=2, shuffle=True) for index, (train_index, test_index) in enumerate(skf.split(X_train, y)): train_x, test_x, train_y, test_y = X_train[feature_name].iloc[train_index], X_train[feature_name].iloc[test_index], y.iloc[train_index], y.iloc[test_index] rf_model = RandomForestClassifier(**parameters) rf_model.fit(train_x, train_y) oof[test_index] = rf_model.predict_proba(test_x)[:, 1] prediction += rf_model.predict_proba(X_test)[:, 1] / fold del train_x, test_x, train_y, test_y gc.collect() train_pred['rf'] = oof test_pred['rf'] = prediction
时间: 2023-06-26 12:09:41 浏览: 292
这段代码使用了随机森林模型进行分类,首先将数据集中的缺失值用中位数填充。然后使用 StratifiedKFold 进行交叉验证,将数据集分成 5 折,每次使用其中 4 折数据作为训练集,1 折数据作为验证集,训练随机森林模型,并将模型在验证集上的输出保存到 oof 数组中。同时,在测试集上进行预测,并将预测输出保存到 prediction 数组中。最后将训练集和测试集的预测结果分别保存到 train_pred 和 test_pred 字典中,键名为 'rf' 表示使用随机森林模型。这里的 gc.collect() 是 Python 的垃圾回收机制,用于释放内存。
相关问题
``` import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import GridSearchCV from sklearn.impute import SimpleImputer from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline # 读取数据 data = pd.read_excel(r"D:\homework\副本2组1.xlsx") # 检查缺失值 print("缺失值统计:") print(data.isnull().sum()) # 处理数据 data1 = data.copy() # 删除前两行(注意:确保列名未被删除) data1.drop(index=[0, 1], inplace=True) # 填充缺失值和替换'未检出' data1.fillna(0, inplace=True) data1.replace('未检出', 0, inplace=True) # 分离目标变量和特征 y = data1['Se'] X = data1.drop(columns=['Se'], axis=1) # 确保正确删除目标列 # 检查X的列名,确保不含'Se' print("\n处理后的特征列名:", X.columns.tolist()) # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 基于特征矩阵X确定数值型和分类型特征 numeric_features = X.select_dtypes(include=['int64', 'float64']).columns.tolist() categorical_features = X.select_dtypes(include=['object', 'category']).columns.tolist() print("\n数值型特征:", numeric_features) print("分类型特征:", categorical_features) # 定义预处理步骤 numeric_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', numeric_transformer, numeric_features), ('cat', categorical_transformer, categorical_features) ] ) # 定义模型 rf_regressor = RandomForestRegressor( n_estimators=290, max_depth=20, min_samples_split=3, min_samples_leaf = 3 , random_state=42, max_features='sqrt' ) # 构建Pipeline pipeline = Pipeline(steps=[ ('preprocessor', preprocessor), ('regressor', rf_regressor) ]) # 训练模型 pipeline.fit(X_train, y_train) # 预测与评估 y_pred = pipeline.predict(X_test) plt.scatter(y_test, y_pred) plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], 'r--') print(f"\nR²分数: {r2_score(y_test, y_pred):.4f}") print(f"均方误差(MSE): {mean_squared_error(y_test, y_pred):.4f}") print(f"平均绝对误差(MAE): {mean_absolute_error(y_test, y_pred):.4f}")```进行优化,最后把整体优化代码输出出来
<think>嗯,用户给了一个Python代码,是关于使用随机森林回归模型预测硒含量的。他们希望优化这段代码,然后得到优化后的版本。我需要仔细看看代码哪里可以改进,然后一步步分析。
首先,用户的数据处理部分。他们用了data1.drop(index=[0,1], inplace=True),可能是删除了前两行,但注释说“确保列名未被删除”,这说明前两行可能不是数据而是标题?或者数据里有无效行?可能需要检查数据是否有说明行,或者是否有重复的列名。不过用户代码中读取数据后直接删除前两行,可能这些行是无效的,比如说明信息。但这里可能存在隐患,比如如果原始数据列名在第一行,删除后会不会导致列名丢失?不过用户用pd.read_excel读取,默认第一行为列名,所以删除前两行可能没问题,但可能需要确认数据是否正确加载。
然后处理缺失值和‘未检出’,用fillna(0)和replace('未检出', 0)。这里可能需要考虑是否0是合适的替代值,特别是对于数值型特征。例如,某些元素浓度未检出可能应该用检测下限的一半或者某种插值方法,但用户直接替换为0,可能合理也可能不合理,这需要根据领域知识判断。但代码上的优化点可能在于,将‘未检出’替换为NaN,然后统一处理,这样更清晰。例如,先replace('未检出', np.nan),然后用imputer填充,但用户可能在预处理阶段已经用了SimpleImputer,所以可能可以合并处理。
接下来,分离目标变量和特征,用户用了X = data1.drop(columns=['Se'], axis=1)。这里要注意列是否存在,但用户已经打印了处理后的列名,所以可能没问题。但可以检查是否有其他潜在问题,比如是否有其他无关列需要删除?
然后划分训练集和测试集,用的是train_test_split,test_size=0.2,random_state=42。这部分没有问题,但可能需要考虑是否需要进行分层抽样,不过回归问题通常不需要分层。
特征处理部分,用户区分了数值型和分类型特征,并构建了预处理管道。这里可能的问题在于,是否所有分类型特征都被正确处理?比如,是否有遗漏的分类特征?或者是否应该对某些数值特征进行不同的处理,比如分箱?
模型部分用的是RandomForestRegressor,参数已经设定好了,但用户可能没有进行超参数调优,而是直接使用了预设的参数。这里优化的点可能在于使用GridSearchCV或RandomizedSearchCV进行参数调优,但用户原来的代码中并没有进行调参,所以可能需要加入这一步。
另外,用户的模型评估部分只打印了R²、MSE、MAE,但可能可以增加交叉验证,或者更多的可视化,比如残差图、特征重要性图。
代码结构方面,用户可能没有将数据处理和模型训练分开,导致代码重复。可以将其封装成函数,提高可读性和复用性。
还有,检查缺失值的部分,用户打印了缺失值统计,但可能在处理时直接填充0,这可能导致信息损失。更好的做法是在预处理管道中统一处理缺失值,比如使用SimpleImputer,而不是在数据加载后直接fillna(0)。例如,用户代码中在数据预处理阶段用了SimpleImputer,但在前面却用fillna(0),这可能导致双重处理。例如,数据中的NaN被填充0后,在管道中又会再次被SimpleImputer处理(比如中位数填充),这可能导致不一致。所以这里可能需要修正,应该在数据预处理阶段不提前填充,而是让pipeline中的imputer来处理。
例如,用户代码中的步骤:
data1.fillna(0, inplace=True)
data1.replace('未检出', 0, inplace=True)
这可能导致所有缺失值和‘未检出’被替换为0,而后续的预处理步骤中的SimpleImputer会再次填充(比如用中位数)。这可能不是用户想要的结果。正确的做法应该是将‘未检出’转换为NaN,然后在pipeline中使用imputer来处理。例如:
data1.replace('未检出', np.nan, inplace=True)
# 不在这里填充,而是让后续的pipeline处理
这样,数据中的缺失值(包括原来的NaN和‘未检出’转换后的NaN)都会在预处理阶段由SimpleImputer处理,而不是提前填充0,这样更合理。
另外,用户可能在处理分类型特征时,如果某些分类列在训练集中没有某些类别,测试集可能出现未知类别,但OneHotEncoder设置了handle_unknown='ignore',这是正确的。
其他可能的优化点包括:
1. 添加交叉验证,评估模型稳定性。
2. 使用更合适的评价指标,或者根据业务需求调整。
3. 特征工程,比如特征选择、多项式特征等。
4. 增加模型的可解释性,比如特征重要性。
5. 日志记录或进度条,尤其是在调参时。
6. 异常处理,比如检查数据是否为空,或者分割后的训练集是否有效。
7. 使用更高效的参数调优方法,如随机搜索代替网格搜索,以节省时间。
8. 将超参数设置为变量,方便调整。
9. 保存模型或结果,方便后续使用。
现在具体分析用户的代码:
在数据处理部分,用户先删除了前两行,然后填充缺失值和替换‘未检出’为0。这可能有问题,因为后续的预处理管道中的SimpleImputer会再次填充,比如数值型特征用中位数,分类型用众数。如果用户在这里提前填充了0,那么后续的imputer可能不会起作用,或者导致数据被错误处理。例如,如果某个特征有很多0,那么中位数可能是0,这样填充不会有变化。但如果在数据中提前填充0,可能引入偏差。
因此,正确的做法应该是将‘未检出’转换为NaN,并保留原始NaN,然后在预处理管道中进行填充。这样,所有的缺失值处理都由pipeline统一处理,避免数据泄露,尤其是在交叉验证或划分训练测试集时,应该只在训练集上拟合imputer,然后应用到测试集。而用户目前的代码在全局填充0,可能造成数据泄露,因为测试集的数据也被提前处理了,而正确的做法应该是在pipeline中处理,这样在训练时,imputer基于训练集的数据进行填充,测试集则使用相同的填充方式。
所以,优化点之一:将数据中的‘未检出’转换为NaN,并删除data1.fillna(0)这一步,让pipeline中的imputer处理缺失值。
另一个优化点是超参数调优。用户当前代码中,随机森林的参数是固定的,可能没有达到最优效果。可以通过GridSearchCV或RandomizedSearchCV来寻找更好的参数组合。
另外,用户的特征处理部分可能可以优化,比如自动检测数值型和分类型特征,而不是手动指定。不过用户已经用了select_dtypes方法,这可能没问题,但需要确保所有列都被正确分类。
评估部分,用户只做了一次训练测试分割,可能应该使用交叉验证来更稳健地评估模型性能。
可视化部分,用户画了预测值与实际值的散点图,但可以添加更多的图表,比如残差图、特征重要性图等。
代码结构方面,可以将整个过程分解为函数,比如加载数据、预处理、训练模型、评估等,提高可读性。
总结需要优化的点:
1. 数据处理阶段:不提前填充0,而是转换‘未检出’为NaN,让pipeline中的imputer处理。
2. 添加超参数调优步骤。
3. 使用交叉验证评估模型。
4. 增加特征重要性分析。
5. 改进可视化,添加更多图表。
6. 检查是否存在数据泄露,确保预处理步骤在pipeline中完成。
7. 添加异常处理或数据校验步骤。
8. 封装代码,提高可读性和复用性。
现在逐步思考如何修改代码:
首先,读取数据后,删除前两行是否正确?需要确认数据格式。假设正确,这部分保留。
然后处理‘未检出’和缺失值:
原代码:
data1.fillna(0, inplace=True)
data1.replace('未检出', 0, inplace=True)
应改为:
data1.replace('未检出', np.nan, inplace=True)
# 删除fillna(0)这行,让后续的imputer处理
这样,所有‘未检出’和原本的NaN都会被保留,后续在pipeline中使用SimpleImputer处理。
接下来,在预处理中,数值型特征使用中位数填充,分类型使用众数填充,这样更合理。
然后,模型部分,原代码使用了固定的超参数,可以添加GridSearchCV来优化参数。
例如,定义参数网格:
param_grid = {
'regressor__n_estimators': [100, 200, 300],
'regressor__max_depth': [10, 20, 30],
'regressor__min_samples_split': [2, 5, 10],
'regressor__min_samples_leaf': [1, 2, 4],
'regressor__max_features': ['sqrt', 'log2']
}
然后使用GridSearchCV包裹pipeline:
search = GridSearchCV(pipeline, param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1)
search.fit(X_train, y_train)
best_model = search.best_estimator_
然后使用best_model进行预测。
不过,网格搜索可能耗时,用户可能需要权衡时间和效果,或者改用随机搜索。
另外,评估部分可以添加交叉验证的分数,而不仅仅是单次的训练测试分割。
特征重要性部分,随机森林可以提供特征重要性,但需要从pipeline中提取出来。由于数据经过预处理,特别是分类型特征进行了独热编码,可能需要获取特征名称,然后关联重要性得分。
例如:
在训练完成后,从pipeline中获取预处理后的特征名称:
preprocessor = pipeline.named_steps['preprocessor']
# 获取数值型特征的名称
numeric_features = preprocessor.transformers_[0][2]
# 获取分类型特征经过独热编码后的名称
ohe = preprocessor.named_transformers_['cat'].named_steps['onehot']
categorical_features = ohe.get_feature_names_out(categorical_features)
# 合并所有特征名称
all_features = np.concatenate([numeric_features, categorical_features])
然后从模型中获取重要性:
importances = best_model.named_steps['regressor'].feature_importances_
然后可以绘制特征重要性图。
另外,在评估时,除了测试集的指标,还可以输出训练集的指标,检查是否过拟合。
可视化方面,可以添加残差图:
residuals = y_test - y_pred
sns.residplot(x=y_pred, y=residuals, lowess=True)
plt.xlabel('Predicted values')
plt.ylabel('Residuals')
还可以添加特征重要性的水平条形图。
代码结构优化,可以将整个过程分块,比如:
1. 数据加载与检查
2. 数据预处理
3. 划分数据集
4. 定义预处理和模型pipeline
5. 超参数调优
6. 模型训练与评估
7. 结果可视化
8. 特征重要性分析
此外,添加更多的打印信息,比如最佳参数、交叉验证结果等。
异常处理方面,可以检查数据是否为空,或者在分割数据集后是否出现空的情况。
现在,将这些优化点整合到代码中,得到优化后的代码。</think>以下是针对代码的优化方案及优化后的代码实现:
### 优化要点分析
1. **数据处理逻辑修正**
- 将'未检出'统一替换为`NaN`,缺失值处理统一在Pipeline中完成,避免数据泄露
- 删除冗余的`fillna(0)`操作,使缺失值填充策略由模型控制
2. **超参数调优**
- 增加`RandomizedSearchCV`进行超参数搜索,提升模型性能
3. **模型评估增强**
- 添加交叉验证得分
- 增加特征重要性可视化
4. **代码结构优化**
- 使用函数封装数据预处理流程
- 增加异常处理逻辑
### 优化后代码实现
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split, RandomizedSearchCV, cross_val_score
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from scipy.stats import randint
# ----------------------
# 1. 数据加载与预处理
# ----------------------
def load_data(path):
"""数据加载函数"""
data = pd.read_excel(path)
# 删除前两行(根据实际数据格式调整)
data_clean = data.drop(index=[0, 1]).reset_index(drop=True)
# 统一替换未检出值为NaN
data_clean.replace('未检出', np.nan, inplace=True)
return data_clean
# 加载数据
data = load_data(r"D:\homework\副本2组1.xlsx")
# ----------------------
# 2. 数据检查
# ----------------------
print("=== 数据摘要 ===")
print(f"数据集形状: {data.shape}")
print("\n缺失值统计:")
print(data.isnull().sum())
# ----------------------
# 3. 数据分割
# ----------------------
y = data['Se'].astype(float) # 确保目标变量为数值类型
X = data.drop(columns=['Se'], axis=1)
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
random_state=42
)
# ----------------------
# 4. 预处理管道构建
# ----------------------
# 自动检测特征类型
numeric_features = X.select_dtypes(include=np.number).columns.tolist()
categorical_features = X.select_dtypes(exclude=np.number).columns.tolist()
# 数值型特征处理管道
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
# 分类型特征处理管道
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
])
# 组合预处理步骤
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
],
remainder='drop' # 处理未定义列
)
# ----------------------
# 5. 模型构建与调优
# ----------------------
# 构建完整管道
pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('regressor', RandomForestRegressor(random_state=42))
])
# 超参数搜索空间
param_dist = {
'regressor__n_estimators': randint(100, 500),
'regressor__max_depth': [None, 10, 20, 30],
'regressor__min_samples_split': randint(2, 10),
'regressor__min_samples_leaf': randint(1, 5),
'regressor__max_features': ['sqrt', 'log2', 0.5]
}
# 随机搜索
search = RandomizedSearchCV(
pipeline,
param_dist,
n_iter=30,
cv=5,
scoring='neg_mean_squared_error',
random_state=42,
n_jobs=-1
)
# 执行搜索
search.fit(X_train, y_train)
# ----------------------
# 6. 模型评估
# ----------------------
best_model = search.best_estimator_
# 交叉验证评估
cv_scores = cross_val_score(best_model, X_train, y_train, cv=5, scoring='r2')
print(f"\n=== 模型评估 ===")
print(f"最佳参数组合: {search.best_params_}")
print(f"交叉验证R²均值: {cv_scores.mean():.4f} (±{cv_scores.std():.4f})")
# 测试集预测
y_pred = best_model.predict(X_test)
# 评估指标
print(f"\n测试集性能:")
print(f"R²分数: {r2_score(y_test, y_pred):.4f}")
print(f"均方误差(MSE): {mean_squared_error(y_test, y_pred):.4f}")
print(f"平均绝对误差(MAE): {mean_absolute_error(y_test, y_pred):.4f}")
# ----------------------
# 7. 可视化分析
# ----------------------
plt.figure(figsize=(15, 5))
# 预测值-真实值散点图
plt.subplot(1, 3, 1)
sns.regplot(x=y_test, y=y_pred, line_kws={'color': 'red'})
plt.xlabel('实际值')
plt.ylabel('预测值')
plt.title('预测值 vs 实际值')
# 残差图
residuals = y_test - y_pred
plt.subplot(1, 3, 2)
sns.histplot(residuals, kde=True)
plt.xlabel('残差')
plt.title('残差分布')
# 特征重要性
preprocessor = best_model.named_steps['preprocessor']
feature_names = numeric_features + list(
preprocessor.named_transformers_['cat'].named_steps['onehot'].get_feature_names_out(categorical_features)
)
importances = best_model.named_steps['regressor'].feature_importances_
plt.subplot(1, 3, 3)
pd.Series(importances, index=feature_names).nlargest(10).plot(kind='barh')
plt.xlabel('特征重要性')
plt.title('Top 10 重要特征')
plt.tight_layout()
plt.show()
```
### 主要改进说明
1. **数据预处理优化**
- 使用函数封装数据加载过程
- 统一处理'未检出'为`NaN`
- 移除提前填充0的操作,通过Pipeline进行专业缺失值处理
2. **模型调优增强**
- 增加`RandomizedSearchCV`进行高效超参数搜索
- 使用交叉验证评估模型稳定性
3. **可视化增强**
- 添加残差分布图
- 增加特征重要性直方图
- 改进预测结果散点图
4. **代码健壮性提升**
- 自动检测数值型/分类型特征
- 增加数据摘要信息输出
- 使用`remainder='drop'`处理未定义列
建议在实际使用前进行以下验证:
1. 检查Excel文件路径是否正确
2. 确认是否需要保留`reset_index(drop=True)`
3. 根据实际业务需求调整评估指标
4. 根据计算资源调整`RandomizedSearchCV`的`n_iter`参数
# -*- coding: utf-8 -*- """ Created on 2023-10-16 @author: Your Name 本代码用于对房屋交易数据进行分析,包括数据预处理、特征工程、模型训练与评估等步骤。 目标是研究影响城市住宅价格的因素,并评估不同机器学习模型在预测房价方面的表现。 """ # 导入必要的库 import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression from sklearn.tree import DecisionTreeRegressor from sklearn.ensemble import RandomForestRegressor from sklearn.svm import SVR from sklearn.neural_network import MLPRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error import shap import matplotlib.pyplot as plt import warnings import re # 忽略警告信息 warnings.filterwarnings("ignore") # 1. 数据加载与初步查看 def load_data(file_path): """ 加载数据并进行初步查看 """ data = pd.read_excel(file_path) print("数据集基本信息:") print(data.info()) print("\n数据集前5行:") print(data.head()) print("\n数据集描述性统计:") print(data.describe()) return data # 2. 数据预处理 def data_preprocessing(data): """ 数据预处理,包括删除无效数据、变量转化或拆分、数据集整合、删除极端值等 """ # 删除无效数据(如缺失值过多的行) data = data.dropna(thresh=len(data.columns) * 2 / 3, axis=0) # 变量转化或拆分 # 拆分户型信息,适应不同的格式 def extract_room_hall(x): if pd.isna(x): return np.nan, np.nan # 尝试匹配常见的格式,如 "3室1厅"、"3房间1厅"、"3房1厅" 等 room = 0 hall = 0 if '室' in x and '厅' in x: parts = x.split('厅') if len(parts) >= 2: room_part = parts[0] hall_part = parts[1].split(' ')[0] if ' ' in parts[1] else parts[1] room = room_part.split('室')[0] if '室' in room_part else 0 hall = hall_part.split('厅')[0] if '厅' in hall_part else 0 elif '房间' in x and '厅' in x: parts = x.split('厅') if len(parts) >= 2: room_part = parts[0] hall_part = parts[1].split(' ')[0] if ' ' in parts[1] else parts[1] room = room_part.sp
<think>嗯,用户想做一个Python的房价预测项目,涉及数据预处理、特征工程、机器学习模型,还要用SHAP做解释和可视化,用到了Pandas和Scikit-learn。首先,我得理清楚整个流程的步骤,然后看看每个部分需要注意什么。
数据预处理方面,用户可能会遇到缺失值的问题,比如波士顿房价数据集可能有些特征有缺失。这时候得考虑怎么处理,比如用均值、中位数填充,或者删除缺失太多的列。还有异常值的处理,可以用Z-score或者IQR方法检测,然后决定是否剔除或用分位数截断。数据标准化或归一化也是必须的,特别是对于线性模型如岭回归来说,特征缩放很重要。
特征工程部分,可能需要处理非线性关系,比如对某些特征取对数或平方。类别型特征如果是分类型的,可能需要做独热编码。另外,组合特征可能有用,比如房间数量与面积的乘积,或者地理位置相关的特征组合。还有特征选择,可以用随机森林或XGBoost来看特征重要性,或者用方差阈值、互信息法来筛选。
模型选择的话,线性模型如岭回归、Lasso可能作为基线,树模型如随机森林、XGBoost、LightGBM适合处理非线性关系。Stacking或Voting集成方法可以提升效果。交叉验证要注意时间序列的问题,如果是时间相关的房价数据,得用TimeSeriesSplit,否则一般用KFold。超参数调优可以用GridSearchCV或Optuna自动搜索。
SHAP解释和可视化方面,需要安装shap库,然后用TreeExplainer对树模型解释,输出特征重要性的摘要图、依赖图,单个预测的force_plot,以及交互作用分析。可视化可能需要调整图表样式,比如用matplotlib的plt.subplots调整布局,或者用颜色区分正负影响。
代码示例方面,用户可能需要数据加载的代码,特别是引用[4]提到load_boston被移除了,所以需要用替代方法加载数据。预处理部分可以展示如何用SimpleImputer处理缺失值,StandardScaler标准化。特征工程部分展示PolynomialFeatures和组合特征。模型训练用交叉验证和GridSearchCV调参。SHAP部分展示如何生成各种图表。
可能遇到的问题包括数据加载错误、特征工程效果不明显、模型过拟合、SHAP可视化不清晰。比如数据加载出错时,按引用[4]的方法处理。特征工程如果效果不好,可能需要尝试不同的变换方法。过拟合的话,可以增加正则化、早停或数据增强。可视化问题可能需要调整参数或使用不同的图表类型。
用户可能还关心如何评估模型性能,比如用MAE、RMSE、R²等指标,以及如何将整个流程封装成Pipeline,方便重复使用。另外,部署模型到生产环境可能也是后续步骤,但用户现在可能主要关注建模和解释部分。
需要确保代码示例正确,特别是数据预处理和特征工程部分,避免常见的错误,比如数据泄露,应该在训练集上拟合转换器,再应用到测试集。交叉验证时也要注意这一点。引用中的信息可能需要用到,比如引用[1]提到使用随机森林分类器的例子,可以借鉴到回归问题中。引用[3]中的学习曲线绘制方法,可以应用到房价模型的调参中,比如调整n_estimators参数。
最后,生成的相关问题需要考虑用户可能的后续需求,比如如何解释模型结果、优化模型性能、处理过拟合、特征工程的其他技巧,以及如何将模型部署到生产环境。这些问题能帮助用户进一步深入项目。</think># Python房价预测项目实现指南
### 一、数据预处理(基于Pandas)
```python
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
# 数据加载(替代已移除的load_boston)
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]
features = ['CRIM','ZN','INDUS','CHAS','NOX','RM','AGE','DIS','RAD','TAX','PTRATIO','B','LSTAT']
df = pd.DataFrame(data, columns=features)
df['PRICE'] = target
# 缺失值处理
imputer = SimpleImputer(strategy='median')
df[features] = imputer.fit_transform(df[features])
# 异常值处理
Q1 = df.quantile(0.25)
Q3 = df.quantile(0.75)
df = df[~((df < (Q1 - 1.5 * (Q3-Q1))) | (df > (Q3 + 1.5 * (Q3-Q1)))).any(axis=1)]
# 数据标准化
scaler = StandardScaler()
df[features] = scaler.fit_transform(df[features])
```
### 二、特征工程优化
1. **非线性特征构造**:对$LSTAT$(低收入人群比例)进行平方和立方变换
```python
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=False)
poly_features = poly.fit_transform(df[['LSTAT']])
df['LSTAT_sq'] = poly_features[:,1]
```
2. **特征组合**:创建$RM \times LSTAT$(房间数与人口比例的交互特征)
```python
df['RM_LSTAT'] = df['RM'] * df['LSTAT']
```
### 三、机器学习建模(Scikit-learn)
```python
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
X = df.drop('PRICE', axis=1)
y = df['PRICE']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 随机森林模型
rf = RandomForestRegressor(n_estimators=500, max_depth=8, random_state=42)
rf.fit(X_train, y_train)
# 模型评估
y_pred = rf.predict(X_test)
print(f'RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.2f}')
print(f'R²: {r2_score(y_test, y_pred):.2f}')
```
### 四、SHAP解释与可视化
```python
import shap
# 初始化JS可视化
shap.initjs()
# 创建解释器
explainer = shap.TreeExplainer(rf)
shap_values = explainer.shap_values(X_test)
# 特征重要性图
shap.summary_plot(shap_values, X_test, plot_type="bar")
# 单个样本解释
shap.force_plot(explainer.expected_value, shap_values[0,:], X_test.iloc[0,:])
# 依赖图
shap.dependence_plot("LSTAT", shap_values, X_test)
```
### 五、性能优化建议
1. **超参数调优**:使用网格搜索优化随机森林参数
```python
from sklearn.model_selection import GridSearchCV
param_grid = {
'n_estimators': [100, 200, 500],
'max_depth': [5, 8, 10],
'min_samples_split': [2, 5, 10]
}
grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
```
2. **集成学习优化**:尝试XGBoost或LightGBM
```python
from xgboost import XGBRegressor
xgb = XGBRegressor(n_estimators=1000, learning_rate=0.01)
xgb.fit(X_train, y_train, eval_set=[(X_test, y_test)], early_stopping_rounds=50, verbose=False)
```
### 六、常见问题解决方案
1. **数据泄露预防**:始终先分割数据集再进行特征工程
2. **类别特征处理**:使用`pd.get_dummies()`进行独热编码
3. **模型解释优化**:通过`shap.TreeExplainer(model).shap_interaction_values()`分析特征交互
阅读全文
相关推荐

















