Day 19 常见的特征筛选算法

@浙大疏锦行

  1. 方差筛选
  2. 皮尔逊相关系数筛选
  3. lasso筛选
  4. 树模型重要性
  5. shap重要性
  6. 递归特征消除REF

面对高维特征,为了减少算力浪费和冗余特征的干扰,通常都会进行特征降维处理。如基因数据、微生物数据、传感器数据等,特征较多

特征降维一般有2种策略:

1. 特征筛选:从n个特征中筛选出m个特征,比如方差筛选,剔除方差过小的特征;利用皮尔逊相关系数筛选;lasso筛选(lasso自带的系数可以理解为重要性)、利用树模型自带的重要性、shap重要性等筛选;特征递归方法

2. 特征组合:从n个特征中组合出m个特征,如pca等

今天主要学习特征筛选:

 方差筛选(简单有效)

它的核心逻辑是:特征的方差反映了数据的变化程度,方差很小的特征几乎没有变化,对模型的预测帮助不大。比如,一个特征的值在所有样本中几乎都一样(方差接近0),那么它对区分不同类别或预测结果几乎没有贡献。因此,方差筛选会设定一个方差阈值,剔除方差低于这个阈值的特征,保留那些变化较大的特征,从而减少特征数量,提高模型效率。

这种方法特别适合处理高维数据,能快速去掉不重要的特征,但它不考虑特征与目标变量之间的关系,可能会误删一些低方差但有意义的特征

# 打印标题,表明这是方差筛选的部分
print("--- 方差筛选 (Variance Threshold) --- ")


# 导入需要的工具库
from sklearn.feature_selection import VarianceThreshold  # 方差筛选工具,用于剔除方差小的特征
import time  # 用于记录代码运行时间,方便比较效率


# 记录开始时间,后面会计算整个过程耗时
start_time = time.time()


# 创建方差筛选器,设置方差阈值为0.01
# 阈值是指方差的最小值,低于这个值的特征会被删除(可以根据数据情况调整阈值)
selector = VarianceThreshold(threshold=0.01)


# 对训练数据进行方差筛选,fit_transform会计算每个特征的方差并剔除不满足阈值的特征
# X_train是原始训练数据,X_train_var是筛选后的训练数据
X_train_var = selector.fit_transform(X_train)


# 对测试数据应用同样的筛选规则,transform会直接用训练数据的筛选结果处理测试数据
# X_test是原始测试数据,X_test_var是筛选后的测试数据
X_test_var = selector.transform(X_test)


# 获取被保留下来的特征名称
# selector.get_support()返回一个布尔值列表,表示哪些特征被保留
# X_train.columns是特征的名称,结合布尔值列表可以提取保留特征的名字
selected_features_var = X_train.columns[selector.get_support()].tolist()


# 打印筛选后保留的特征数量和具体特征名称,方便查看结果
print(f"方差筛选后保留的特征数量: {len(selected_features_var)}")
print(f"保留的特征: {selected_features_var}")


# 创建一个逻辑回归模型,用于在筛选后的数据上进行训练和预测
# 保持与基准模型一致,使用相同的参数设置
lr_model_var = LogisticRegression(random_state=42)


# 在筛选后的训练数据上训练模型
# X_train_var是筛选后的特征数据,y_train是对应的目标标签
lr_model_var.fit(X_train_var, y_train)


# 使用训练好的模型对筛选后的测试数据进行预测
# X_test_var是筛选后的测试特征数据,lr_pred_var是预测结果
lr_pred_var = lr_model_var.predict(X_test_var)


# 记录结束时间,计算整个训练和预测过程的耗时
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")


# 打印模型在测试集上的分类报告,展示模型的性能
print("\n方差筛选后逻辑回归在测试集上的分类报告:")
print(classification_report(y_test, lr_pred_var))


# 打印混淆矩阵,展示模型预测的详细结果
print("方差筛选后逻辑回归在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, lr_pred_var))
--- 方差筛选 (Variance Threshold) ---
方差筛选后保留的特征数量: 25
保留的特征: ['age', 'trestbps', 'chol', 'thalach', 'oldpeak', 'sex_1', 'cp_1', 'cp_2', 'cp_3', 'fbs_1', 'restecg_1', 'restecg_2', 'exang_1', 'slope_1', 'slope_2', 'ca_1', 'ca_2', 'ca_3', 'ca_4', 'thal_1', 'thal_2', 'thal_3', 'thalach_age_ratio', 'bp_chol_risk', 'st_depression_ratio']
训练与预测耗时: 0.0123 秒

方差筛选后逻辑回归在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.87      0.93      0.90        29
           1       0.93      0.88      0.90        32

    accuracy                           0.90        61
   macro avg       0.90      0.90      0.90        61
weighted avg       0.90      0.90      0.90        61

方差筛选后逻辑回归在测试集上的混淆矩阵:
[[27  2]
 [ 4 28]]

因为这个数据集特征本来就不是很多,主要来熟悉流程。

皮尔逊相关系数筛选

核心是通过计算 每个特征与目标变量的线性相关程度 来筛选重要特征。

关键要点:
1. 1.
   原理 :皮尔逊相关系数(范围-1到1)衡量两个连续变量的线性相关强度——绝对值越大,相关性越强(接近1正相关,接近-1负相关,0无线性相关)。
2. 2.
   筛选逻辑 :计算所有特征与目标变量的相关系数,保留绝对值超过设定阈值的特征(如|r|>0.3),剔除低相关特征。
3. 3.
   适用场景 :主要用于 目标变量为连续型 的任务;若目标是分类变量(如0/1标签),需先将其编码为数值(如one-hot编码)再计算。
简单说,就是挑出与目标变量“线性关系最密切”的特征,减少冗余,提升模型效率。

# 打印标题,表明这是皮尔逊相关系数筛选的部分
print("--- 皮尔逊相关系数筛选 (Pearson Correlation) --- ")

# 导入需要的工具库
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif  # 用于分类问题的ANOVA F值
import time

# 记录开始时间
start_time = time.time()

# 计算特征与目标变量之间的皮尔逊相关系数
# 注意:SelectKBest默认使用f_classif(ANOVA F值),对于分类问题更合适
# 我们可以通过mutual_info_classif获取互信息,或者使用SelectKBest配合相关系数

# 对于分类问题,使用f_classif(ANOVA F值)来衡量特征重要性
selector_pearson = SelectKBest(score_func=f_classif, k=10)  # 选择前10个最重要的特征

# 拟合数据并转换
X_train_pearson = selector_pearson.fit_transform(X_train, y_train)
X_test_pearson = selector_pearson.transform(X_test)

# 获取被保留下来的特征名称
selected_features_pearson = X_train.columns[selector_pearson.get_support()].tolist()

# 打印筛选后保留的特征数量和具体特征名称
print(f"皮尔逊相关系数筛选后保留的特征数量: {len(selected_features_pearson)}")
print(f"保留的特征: {selected_features_pearson}")

# 创建逻辑回归模型
lr_model_pearson = LogisticRegression(random_state=42)

# 在筛选后的训练数据上训练模型
lr_model_pearson.fit(X_train_pearson, y_train)

# 预测
lr_pred_pearson = lr_model_pearson.predict(X_test_pearson)

# 记录结束时间
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")

# 打印分类报告
print("\n皮尔逊相关系数筛选后逻辑回归在测试集上的分类报告:")
print(classification_report(y_test, lr_pred_pearson))

# 打印混淆矩阵
print("皮尔逊相关系数筛选后逻辑回归在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, lr_pred_pearson))

--- 皮尔逊相关系数筛选 (Pearson Correlation) ---
皮尔逊相关系数筛选后保留的特征数量: 10
保留的特征: ['thalach', 'oldpeak', 'sex_1', 'cp_2', 'exang_1', 'slope_1', 'slope_2', 'ca_1', 'thal_2', 'thal_3']
训练与预测耗时: 0.0279 秒

皮尔逊相关系数筛选后逻辑回归在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.84      0.90      0.87        29
           1       0.90      0.84      0.87        32

    accuracy                           0.87        61
   macro avg       0.87      0.87      0.87        61
weighted avg       0.87      0.87      0.87        61

皮尔逊相关系数筛选后逻辑回归在测试集上的混淆矩阵:
[[26  3]
 [ 5 27]]

--- 特征选择方法比较 ---
原始特征数量: 25
方差筛选保留特征数量: 25
皮尔逊相关系数筛选保留特征数量: 10
基准模型准确率: 0.9016
方差筛选模型准确率: 0.9016
皮尔逊相关系数筛选模型准确率: 0.8689

Lasso回归(Least Absolute Shrinkage and Selection Operator)是一种结合特征选择和模型训练的方法。它的核心逻辑是:在进行线性回归的同时,通过引入L1正则化项(即惩罚项),强制将一些不重要特征的回归系数压缩到0,从而实现特征筛选。换句话说,Lasso会自动“挑选”对预测目标有贡献的特征(系数不为0),而剔除无关或冗余的特征(系数为0)。这种方法特别适合处理高维数据,可以减少特征数量,提高模型的解释性和计算效率。

# 打印标题,表明这是Lasso筛选的部分
print("--- Lasso筛选 (L1正则化) --- ")

# 导入需要的工具库
from sklearn.linear_model import LogisticRegressionCV
import time

# 记录开始时间
start_time = time.time()

# 创建Lasso逻辑回归模型(使用L1正则化)
# Cs参数表示正则化强度的候选值数量,cv表示交叉验证折数
lasso_model = LogisticRegressionCV(penalty='l1', solver='liblinear', Cs=10, cv=5, random_state=42)

# 拟合数据
lasso_model.fit(X_train, y_train)

# 获取非零系数的特征(即被选中的特征)
selected_features_lasso = X_train.columns[lasso_model.coef_[0] != 0].tolist()

# 筛选特征
X_train_lasso = X_train[selected_features_lasso]
X_test_lasso = X_test[selected_features_lasso]

# 打印筛选后保留的特征数量和具体特征名称
print(f"Lasso筛选后保留的特征数量: {len(selected_features_lasso)}")
print(f"保留的特征: {selected_features_lasso}")

# 使用筛选后的特征重新训练逻辑回归模型
lr_model_lasso = LogisticRegression(random_state=42)
lr_model_lasso.fit(X_train_lasso, y_train)

# 预测
lr_pred_lasso = lr_model_lasso.predict(X_test_lasso)

# 记录结束时间
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")

# 打印分类报告
print("\nLasso筛选后逻辑回归在测试集上的分类报告:")
print(classification_report(y_test, lr_pred_lasso))

# 打印混淆矩阵
print("Lasso筛选后逻辑回归在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, lr_pred_lasso))

--- Lasso筛选 (L1正则化) ---
Lasso筛选后保留的特征数量: 22
保留的特征: ['age', 'trestbps', 'chol', 'thalach', 'oldpeak', 'sex_1', 'cp_1', 'cp_2', 'cp_3', 'fbs_1', 'restecg_1', 'exang_1', 'slope_2', 'ca_1', 'ca_2', 'ca_3', 'ca_4', 'thal_2', 'thal_3', 'thalach_age_ratio', 'bp_chol_risk', 'st_depression_ratio']
训练与预测耗时: 0.0945 秒

Lasso筛选后逻辑回归在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.84      0.93      0.89        29
           1       0.93      0.84      0.89        32

    accuracy                           0.89        61
   macro avg       0.89      0.89      0.89        61
weighted avg       0.89      0.89      0.89        61

Lasso筛选后逻辑回归在测试集上的混淆矩阵:
[[27  2]
 [ 5 27]]

--- 特征选择方法比较 ---
原始特征数量: 25
方差筛选保留特征数量: 25
皮尔逊相关系数筛选保留特征数量: 10
Lasso筛选保留特征数量: 22
基准模型准确率: 0.9016
方差筛选模型准确率: 0.9016
皮尔逊相关系数筛选模型准确率: 0.8689
Lasso筛选模型准确率: 0.8852

要注意,lasso本质上是回归模型,实际上用这个方法来筛选也是用回归模型对分类问题建模结束了,然后打印特征重要度,她是把0和1目标变量视为连续值来进行回归的。效果会差一点,不符合逻辑,但是确实可以计算

树模型重要性筛选
基于决策树、随机森林等树模型,通过计算特征在节点分裂时的贡献度(如信息增益)评估重要性,简单直观、能处理特征交互,但可能高估相关特征中某一个的重要性,适用于快速初步筛选。

SHAP重要性筛选
基于博弈论Shapley值,量化每个特征对预测的边际贡献,同时考虑特征依赖关系,理论严谨、能解释单个预测结果(正负影响方

向),计算成本较高,适用于需深入理解特征影响的场景。

递归特征消除(RFE)
迭代式特征选择方法:从所有特征开始,训练模型→移除最不重要特征→重复,直到目标特征数。考虑特征交互、无需人为设阈值,计算复杂度高(需多次训练模型),适用于系统减少特征维度的场景。

# 打印标题,表明这是树模型重要性筛选的部分
print("--- 树模型重要性筛选 (Random Forest) --- ")

# 导入需要的工具库
from sklearn.ensemble import RandomForestClassifier
import time

# 记录开始时间
start_time = time.time()

# 创建随机森林模型
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)

# 获取特征重要性
feature_importance = rf_model.feature_importances_

# 排序并选择前10个重要特征
indices = np.argsort(feature_importance)[::-1][:10]
selected_features_rf = X_train.columns[indices].tolist()

# 筛选特征
X_train_rf = X_train[selected_features_rf]
X_test_rf = X_test[selected_features_rf]

# 打印筛选后保留的特征数量和具体特征名称
print(f"树模型重要性筛选后保留的特征数量: {len(selected_features_rf)}")
print(f"保留的特征: {selected_features_rf}")

# 使用筛选后的特征重新训练逻辑回归模型
lr_model_rf = LogisticRegression(random_state=42)
lr_model_rf.fit(X_train_rf, y_train)

# 预测
lr_pred_rf = lr_model_rf.predict(X_test_rf)

# 记录结束时间
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")

# 打印分类报告
print("\n树模型重要性筛选后逻辑回归在测试集上的分类报告:")
print(classification_report(y_test, lr_pred_rf))

# 打印混淆矩阵
print("树模型重要性筛选后逻辑回归在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, lr_pred_rf))

# 打印标题,表明这是SHAP重要性筛选的部分
print("--- SHAP重要性筛选 --- ")

# 导入需要的工具库
import shap
import time

# 记录开始时间
start_time = time.time()

# 使用随机森林模型进行SHAP分析
# 创建解释器
explainer = shap.TreeExplainer(rf_model)

# 计算SHAP值
shap_values = explainer.shap_values(X_train)

# 获取特征重要性(使用SHAP值的绝对值均值)
shap_importance = np.abs(shap_values[1]).mean(0)

# 排序并选择前10个重要特征
indices = np.argsort(shap_importance)[::-1][:10]
selected_features_shap = X_train.columns[indices].tolist()

# 筛选特征
X_train_shap = X_train[selected_features_shap]
X_test_shap = X_test[selected_features_shap]

# 打印筛选后保留的特征数量和具体特征名称
print(f"SHAP重要性筛选后保留的特征数量: {len(selected_features_shap)}")
print(f"保留的特征: {selected_features_shap}")

# 使用筛选后的特征重新训练逻辑回归模型
lr_model_shap = LogisticRegression(random_state=42)
lr_model_shap.fit(X_train_shap, y_train)

# 预测
lr_pred_shap = lr_model_shap.predict(X_test_shap)

# 记录结束时间
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")

# 打印分类报告
print("\nSHAP重要性筛选后逻辑回归在测试集上的分类报告:")
print(classification_report(y_test, lr_pred_shap))

# 打印混淆矩阵
print("SHAP重要性筛选后逻辑回归在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, lr_pred_shap))

# 打印标题,表明这是递归特征消除(RFE)的部分
print("--- 递归特征消除 (RFE) --- ")

# 导入需要的工具库
from sklearn.feature_selection import RFE
import time

# 记录开始时间
start_time = time.time()

# 创建逻辑回归模型作为RFE的基模型
estimator = LogisticRegression(random_state=42)

# 创建RFE对象,选择10个特征
rfe = RFE(estimator=estimator, n_features_to_select=10, step=1)

# 拟合数据
rfe.fit(X_train, y_train)

# 获取被保留下来的特征名称
selected_features_rfe = X_train.columns[rfe.support_].tolist()

# 筛选特征
X_train_rfe = X_train[selected_features_rfe]
X_test_rfe = X_test[selected_features_rfe]

# 打印筛选后保留的特征数量和具体特征名称
print(f"RFE筛选后保留的特征数量: {len(selected_features_rfe)}")
print(f"保留的特征: {selected_features_rfe}")

# 使用筛选后的特征重新训练逻辑回归模型
lr_model_rfe = LogisticRegression(random_state=42)
lr_model_rfe.fit(X_train_rfe, y_train)

# 预测
lr_pred_rfe = lr_model_rfe.predict(X_test_rfe)

# 记录结束时间
end_time = time.time()
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")

# 打印分类报告
print("\nRFE筛选后逻辑回归在测试集上的分类报告:")
print(classification_report(y_test, lr_pred_rfe))

# 打印混淆矩阵
print("RFE筛选后逻辑回归在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, lr_pred_rfe))
--- 树模型重要性筛选 (Random Forest) ---
树模型重要性筛选后保留的特征数量: 10
保留的特征: ['thal_2', 'thalach', 'exang_1', 'oldpeak', 'age', 'thalach_age_ratio', 'st_depression_ratio', 'chol', 'bp_chol_risk', 'trestbps']
训练与预测耗时: 0.1133 秒

树模型重要性筛选后逻辑回归在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.81      0.86      0.83        29
           1       0.87      0.81      0.84        32

    accuracy                           0.84        61
   macro avg       0.84      0.84      0.84        61
weighted avg       0.84      0.84      0.84        61

树模型重要性筛选后逻辑回归在测试集上的混淆矩阵:
[[25  4]
 [ 6 26]]
--- SHAP重要性筛选 ---
SHAP重要性筛选后保留的特征数量: 10
保留的特征: ['thal_2', 'exang_1', 'thal_3', 'oldpeak', 'thalach', 'slope_2', 'ca_1', 'age', 'cp_2', 'sex_1']
训练与预测耗时: 0.1685 秒

SHAP重要性筛选后逻辑回归在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.81      0.90      0.85        29
           1       0.90      0.81      0.85        32

    accuracy                           0.85        61
   macro avg       0.85      0.85      0.85        61
weighted avg       0.86      0.85      0.85        61

SHAP重要性筛选后逻辑回归在测试集上的混淆矩阵:
[[26  3]
 [ 6 26]]
--- 递归特征消除 (RFE) ---
RFE筛选后保留的特征数量: 10
保留的特征: ['oldpeak', 'sex_1', 'cp_2', 'cp_3', 'exang_1', 'slope_1', 'ca_1', 'ca_2', 'ca_3', 'thal_3']
训练与预测耗时: 0.0443 秒

RFE筛选后逻辑回归在测试集上的分类报告:
              precision    recall  f1-score   support

           0       0.86      0.86      0.86        29
           1       0.88      0.88      0.88        32

    accuracy                           0.87        61
   macro avg       0.87      0.87      0.87        61
weighted avg       0.87      0.87      0.87        61

RFE筛选后逻辑回归在测试集上的混淆矩阵:
[[25  4]
 [ 4 28]]

--- 特征选择方法比较 ---
原始特征数量: 25
方差筛选保留特征数量: 25
皮尔逊相关系数筛选保留特征数量: 10
Lasso筛选保留特征数量: 22
树模型重要性筛选保留特征数量: 10
SHAP重要性筛选保留特征数量: 10
RFE筛选保留特征数量: 10
基准模型准确率: 0.9016
方差筛选模型准确率: 0.9016
皮尔逊相关系数筛选模型准确率: 0.8689
Lasso筛选模型准确率: 0.8852
树模型重要性筛选模型准确率: 0.8361
SHAP重要性筛选模型准确率: 0.8525
RFE筛选模型准确率: 0.8689

任务概述 此任务中,我们要完成三项任务: 使用随机森林算法完成基本建模任务 基本任务需要我们处理数据,观察特征,完成建模并进行可视化展示分析 观察数据量与特征个数对结果影响 在保证算法一致的前提下, 加大数据个数,观察结果变换。重新考虑特征工程,引入新特征后观察结果走势。 对随机森林算法进行调参,找到最合适的参数 掌握机器学习中两种经典调参方法,对当前模型进行调节 数据展示 # Pandas is used for data manipulation import pandas as pd # Read in data as pandas dataframe and display first 5 rows features = pd.read_csv('data/temps.csv') features.head(5) AI写代码 python 运行 1 2 3 4 5 6 本数据表中: year,moth,day,wek分别表示的具体的时间 temp_ 2:前天的最高温度值 temp_ 1:昨天的最高温度值 average: 在历史中,每年这一天的平均最高温度值 actual: 这就是我们的标签值了,当天的真实最高温度 friend: 朋友的评价 #查看数据维度 print('The shape of our features is:', features.shape) #查看有无异常值 features.describe() AI写代码 python 运行 1 2 3 4 无异常值我们就可以接着往下做了 在此数据集中,我们可以看到关于时间的特征是分散的,下面我们需要把他们合并一下,得到一个datetime格式的特征数据 # 处理时间数据 import datetime # 分别得到年月日 years = features['year'] months = features['month'] days = features['day'] # datetime格式 dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)] dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates] AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 查看数据 # 准备画图 import matplotlib.pyplot as plt %matplotlib inline # 指定默认风格 plt.style.use('fivethirtyeight') # 设计布局 fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize = (10,10)) fig.autofmt_xdate(rotation = 45) # 标签值 ax1.plot(dates, features['actual']) ax1.set_xlabel(''); ax1.set_ylabel('Temperature'); ax1.set_title('Max Temp') # 昨天 ax2.plot(dates, features['temp_1']) ax2.set_xlabel(''); ax2.set_ylabel('Temperature'); ax2.set_title('Previous Max Temp') # 前天 ax3.plot(dates, features['temp_2']) ax3.set_xlabel('Date'); ax3.set_ylabel('Temperature'); ax3.set_title('Two Days Prior Max Temp') # 朋友的评价 ax4.plot(dates, features['friend']) ax4.set_xlabel('Date'); ax4.set_ylabel('Temperature'); ax4.set_title('Friend Estimate') plt.tight_layout(pad=2) AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 得到可视化信息如下: 横轴为日期,纵轴分别是 actual、temp_1、temp_2、friend 基本随机森林模型建立 数据预处理 在文章一开始的观察数据的那一步,我们就发现了一个问题,week 特征它不是数字形式,而是 Mon、Tue、Wed、Thu、Fri、Sat、Sun 使用 独热编码 One-Hot Encoding 方式进行数据处理,使其全部成为数字形式,这里我们使用 pd.get_dummies(),它的 官网API # 独热编码 pd.get_dummies自动寻找 features = pd.get_dummies(features) features.head(5) AI写代码 python 运行 1 2 3 标签与数据集格式转换 # 数据与标签 import numpy as np # 标签 labels = np.array(features['actual']) # 在特征中去掉标签 features= features.drop('actual', axis = 1) # 保存特征名称,后续使用 feature_list = list(features.columns) # 转换为 np.array形式 features = np.array(features) AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 训练集与测试集 # 使用 Skicit-learn 切分数据集 from sklearn.model_selection import train_test_split # 将数据分为训练集和测试集 // 传入参数:特征、标签、比例、随机种子 train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size = 0.25, random_state = 42) AI写代码 python 运行 1 2 3 4 5 建立一个基础的随机森林模型 所有准备工作都已经完成了,现在可以来建立随机森林模型了,导入Sklearn工具包,在这里我们先建立1000个树模型尝试一下,其他参数先用默认值,之后再细化调参任务 # 导入随机森林算法模型 from sklearn.ensemble import RandomForestRegressor # 实例化模型 rf = RandomForestRegressor(n_estimators= 1000, random_state=42) # 训练数据模型 rf.fit(train_features, train_labels) AI写代码 python 运行 1 2 3 4 5 6 测试 # 在测试数据上使用森林预测方法 predictions = rf.predict(test_features) # 计算绝对误差 errors = abs(predictions - test_labels) # 计算绝对百分比误差 mape = 100*(errors/test_labels) accuracy = 100 - np.mean(mape) # 打印出平均绝对误差(mae) print('Mean Absolute Error:', round(np.mean(errors), 2),) # 打印准确率 print('Accuracy:', round(accuracy,2),'%') AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 Mean Absolute Error: 3.83 Accuracy: 93.99 % AI写代码 1 2 预测指标 MAE、MAPE: MAE: 平均绝对误差(Mean Absolute Error) M A E = 1 n ∑ i = 1 n ∣ y ^ i − y i ∣ MAE=\frac{1}{n}\sum_{i=1}^{n}|\hat{y}_i-yi| MAE= n 1 ​ i=1 ∑ n ​ ∣ y ^ ​ i ​ −yi∣ 值域:[0,+∞) 当预测值与真实值完全吻合时等于0,即完美模型;误差越大,MAE 值越大。 MAPE: 平均绝对百分比误差(Mean Absolute Percentage Error) M A P E = 100 % n ∑ i = 1 n ∣ y ^ i − y i y i ∣ MAPE=\frac{100\%}{n}\sum_{i=1}^{n}|\frac{\hat{y}_i-yi}{y_i}| MAPE= n 100% ​ i=1 ∑ n ​ ∣ y i ​ y ^ ​ i ​ −yi ​ ∣ 值域:[0,+∞),MAPE 为0%表示完美模型,MAPE 大于 100 %则表示劣质模型。 但 MAPE 有一点需要注意,当真实值 y i y_iy i ​ 有数据等于0时,存在分母 0 00 除问题,则该公式无意义不可用 可视化展示与特征重要性 树模型的可视化需要安装软件库 Graphviz,并好相关环境变量 graphviz-2.38.msi 官方下载地址:https://graphviz.gitlab.io/_pages/Download/Download_windows.html # 导入工具包 from sklearn.tree import export_graphviz import pydot #pip install pydot # 拿到其中的一棵树 tree = rf.estimators_[5] # 将图像导出为 dot 文件 export_graphviz(tree, out_file = 'tree.dot', feature_names = feature_list, rounded = True, precision = 1) # 绘图 (graph, ) = pydot.graph_from_dot_file('tree.dot') # 展示 graph.write_png('tree.png'); AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 生成的原始图像文件中,树的深度是15,下面我们简化一下,将树的深度改为3,再看一下 # 限制树模型深度 rf_small = RandomForestRegressor(n_estimators=10, max_depth = 3, random_state=42) rf_small.fit(train_features, train_labels) # 拿到其中的一棵树 tree_small = rf_small.estimators_[5] # 将图像导出为 dot 文件 export_graphviz(tree_small, out_file = 'small_tree.dot', feature_names = feature_list, rounded = True, precision = 1) # 绘图 (graph, ) = pydot.graph_from_dot_file('small_tree.dot') # 展示 graph.write_png('small_tree.png'); AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 这张图像显示的即是树模型的上面的形状 解释: 特征重要性 # 得到特征重要性 importances = list(rf.feature_importances_) # 转换格式 feature_importances = [(feature, round(importance, 2)) for feature, importance in zip(feature_list, importances)] # 排序 feature_importances = sorted(feature_importances, key = lambda x: x[1], reverse = True) # 对应进行打印 [print('Variable: {:20} Importance: {}'.format(*pair)) for pair in feature_importances]; AI写代码 python 运行 1 2 3 4 5 6 7 8 Variable: temp_1 Importance: 0.7 Variable: average Importance: 0.19 Variable: day Importance: 0.03 Variable: temp_2 Importance: 0.02 Variable: friend Importance: 0.02 Variable: month Importance: 0.01 Variable: year Importance: 0.0 Variable: week_Fri Importance: 0.0 Variable: week_Mon Importance: 0.0 Variable: week_Sat Importance: 0.0 Variable: week_Sun Importance: 0.0 Variable: week_Thurs Importance: 0.0 Variable: week_Tues Importance: 0.0 Variable: week_Wed Importance: 0.0 AI写代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 画图展示 # 生成X轴坐标位置 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] x_values = list(range(len(importances))) # 绘图 plt.bar(x_values, importances, orientation = 'vertical') # 定义各柱状图名称 plt.xticks(x_values, feature_list, rotation='vertical') # X、Y轴设定 plt.ylabel('Importance') plt.xlabel('Variable') # 图片名称 plt.title('Variable Importances') AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 用最重要的特征再来试试 得到了我们的特征重要性之后,我们可以了解到模型训练时用到的主要特征是 temp_1、average,那么我们就来看一下,如果只用这两个特征进行训练,效果会是什么样子,会不会对结果无影响 # 选择最重要的两个特征来实验 rf_most_important = RandomForestRegressor(n_estimators= 1000, random_state=42) # 拿到特征值 important_indices = [feature_list.index('temp_1'), feature_list.index('average')] train_important = train_features[:, important_indices] test_important = test_features[:, important_indices] # 重新训练模型 rf_most_important.fit(train_important, train_labels) # 预测结果 predictions = rf_most_important.predict(test_important) # 计算绝对误差 errors = abs(predictions - test_labels) # 计算 MAPE mape = np.mean(100 * (errors / test_labels)) accuracy = 100 - mape # 打印 print('Mean Absolute Error:', round(np.mean(errors), 2)) print('Accuracy:', round(accuracy, 2), '%') AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Mean Absolute Error: 3.92 Accuracy: 93.77 % AI写代码 1 2 使用所有特征训练时:Mean Absolute Error: 3.83,Accuracy: 93.99 %;使用两个特征训练时:Mean Absolute Error: 3.92,Accuracy: 93.77 %。数据集共有15个特征,在经过特征重要性筛选后我们使用的是2个特征,训练速度肯定是变快了,但是精度值有一点下降。在实际应用场景中,我们可以根据应用场景中是更注重预测速度还是更注重预测精度来进行模型选择。 预测值与真实值之间的差异 最后我们将本文中做的实验结果进行整合 # 日期数据 months = features[:, feature_list.index('month')] days = features[:, feature_list.index('day')] years = features[:, feature_list.index('year')] # 转换日期格式 dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)] dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates] # 创建一个表格来存日期和其对应的标签数值 true_data = pd.DataFrame(data = {'date': dates, 'actual': labels}) # 再创建一个表格来存日期和其对应的标签数值 months = test_features[:, feature_list.index('month')] days = test_features[:, feature_list.index('day')] years = test_features[:, feature_list.index('year')] # Column of dates test_dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)] # Convert to datetime objects test_dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in test_dates] # Dataframe with predictions and dates predictions_data = pd.DataFrame(data = {'date': test_dates, 'prediction': predictions}) AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 真实值 plt.plot(true_data['date'], true_data['actual'], 'b-', label = 'actual') # 预测值 plt.plot(predictions_data['date'], predictions_data['prediction'], 'ro', label = 'prediction') plt.xticks(rotation = '60'); plt.legend() # 画图 plt.xlabel('Date') plt.ylabel('Maximum Temperature (F)') plt.title('Actual and Predicted Values') AI写代码 python 运行 1 2 3 4 5 6 7 8 9 10 此图显示出数据的走势,证明我们已经基本能够掌握此模型了,接下来就是要深入到数据中,做更精细的调整! ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.youkuaiyun.com/qq_42549612/article/details/105304889帮我写一份报告
最新发布
08-08
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值