一、实验目的

  1. 掌握使用 scikit-learn 进行数据加载、预处理和划分的方法
  2. 熟悉 scikit-learn 中机器学习的基本流程和核心组件
  3. 学习使用 scikit-learn 处理结构化数据的基本技巧

二、实验环境

  • Python 3.8+
  • 主要库:pandas, numpy, scikit-learn, matplotlib, seaborn

三、scikit-learn 核心组件介绍

1. scikit-learn 模块结构

scikit-learn 提供了统一的API接口,主要包含以下核心模块:

# 数据预处理

from sklearn.preprocessing import StandardScaler, MinMaxScaler, LabelEncoder

# 模型选择

from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV

# 线性模型

from sklearn.linear_model import LinearRegression, LogisticRegression

# 树模型

from sklearn.tree import DecisionTreeRegressor, DecisionTreeClassifier

# 集成方法

from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor

# 聚类算法

from sklearn.cluster import KMeans, DBSCAN

# 模型评估

from sklearn.metrics import mean_squared_error, r2_score, accuracy_score, classification_report

2. scikit-learn 统一API设计

所有scikit-learn estimator都遵循统一的接口设计:

  • fit(): 训练模型
  • predict(): 进行预测
  • score(): 评估模型
  • transform(): 数据转换(预处理器)

四、数据加载与探索

1. 加载网约车司机数据集

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

from sklearn.model_selection import train_test_split

from sklearn.preprocessing import StandardScaler

from sklearn.linear_model import LinearRegression

from sklearn.ensemble import RandomForestRegressor

from sklearn.metrics import mean_squared_error, r2_score

# 加载数据

df = pd.read_excel("网约车司机单日工作情况.xlsx")

# 数据基本信息探索

print("数据集形状:", df.shape)

print("\n数据基本信息:")

print(df.info())

print("\n数据描述性统计:")

print(df.describe())

print("\n缺失值检查:")

print(df.isnull().sum())

2. 数据可视化分析

# 设置中文字体

plt.rcParams['font.sans-serif'] = ['SimHei']

plt.rcParams['axes.unicode_minus'] = False

# 创建可视化图表

fig, axes = plt.subplots(2, 3, figsize=(15, 10))

# 车费收入分布

axes[0,0].hist(df['车费收入'], bins=30, alpha=0.7, color='skyblue')

axes[0,0].set_title('车费收入分布')

axes[0,0].set_xlabel('收入')

axes[0,0].set_ylabel('频数')

# 在线时长分布

axes[0,1].hist(df['在线时长'], bins=30, alpha=0.7, color='lightgreen')

axes[0,1].set_title('在线时长分布')

axes[0,1].set_xlabel('时长(小时)')

# 完成订单数分布

axes[0,2].hist(df['完成订单数'], bins=30, alpha=0.7, color='orange')

axes[0,2].set_title('完成订单数分布')

axes[0,2].set_xlabel('订单数')

# 收入与在线时长关系

axes[1,0].scatter(df['在线时长'], df['车费收入'], alpha=0.5)

axes[1,0].set_title('收入 vs 在线时长')

axes[1,0].set_xlabel('在线时长(小时)')

axes[1,0].set_ylabel('收入')

# 收入与订单数关系

axes[1,1].scatter(df['完成订单数'], df['车费收入'], alpha=0.5)

axes[1,1].set_title('收入 vs 完成订单数')

axes[1,1].set_xlabel('完成订单数')

axes[1,1].set_ylabel('收入')

# 相关性热力图

corr_matrix = df[['平均星级', '在线时长', '完成订单数', '订单实际总公里数', '车费收入']].corr()

sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', ax=axes[1,2])

axes[1,2].set_title('特征相关性热力图')

plt.tight_layout()

plt.show()

五、数据预处理与特征工程

1. 特征选择与数据划分

# 特征选择 - 排除司机编号(ID类特征)

features = ['平均星级', '在线时长', '完成订单数', '订单实际总公里数']

target = '车费收入'

X = df[features]

y = df[target]

print("特征矩阵形状:", X.shape)

print("目标变量形状:", y.shape)

# 数据划分 - 训练集80%,测试集20%

X_train, X_test, y_train, y_test = train_test_split(

    X, y,

    test_size=0.2,

    random_state=42,

    shuffle=True

)

print(f"训练集样本数: {X_train.shape[0]}")

print(f"测试集样本数: {X_test.shape[0]}")

2. 数据标准化

# 使用StandardScaler进行数据标准化

scaler = StandardScaler()

# 只在训练集上拟合scaler,然后转换训练集和测试集

X_train_scaled = scaler.fit_transform(X_train)

X_test_scaled = scaler.transform(X_test)

print("标准化后的训练集统计:")

print(f"均值: {X_train_scaled.mean(axis=0)}")

print(f"标准差: {X_train_scaled.std(axis=0)}")

六、模型训练与评估

1. 线性回归模型

# 初始化线性回归模型

lr_model = LinearRegression()

# 训练模型

lr_model.fit(X_train_scaled, y_train)

# 预测

y_pred_lr = lr_model.predict(X_test_scaled)

# 评估模型

lr_mse = mean_squared_error(y_test, y_pred_lr)

lr_r2 = r2_score(y_test, y_pred_lr)

print("=== 线性回归模型表现 ===")

print(f"均方误差(MSE): {lr_mse:.2f}")

print(f"R² 分数: {lr_r2:.4f}")

# 特征重要性(系数)

feature_importance = pd.DataFrame({

    '特征': features,

    '系数': lr_model.coef_

}).sort_values('系数', key=abs, ascending=False)

print("\n特征系数:")

print(feature_importance)

2. 随机森林回归模型

# 初始化随机森林模型

rf_model = RandomForestRegressor(

    n_estimators=100,

    max_depth=10,

    random_state=42

)

# 训练模型

rf_model.fit(X_train, y_train)  # 树模型通常不需要标准化

# 预测

y_pred_rf = rf_model.predict(X_test)

# 评估模型

rf_mse = mean_squared_error(y_test, y_pred_rf)

rf_r2 = r2_score(y_test, y_pred_rf)

print("=== 随机森林模型表现 ===")

print(f"均方误差(MSE): {rf_mse:.2f}")

print(f"R² 分数: {rf_r2:.4f}")

# 特征重要性

rf_feature_importance = pd.DataFrame({

    '特征': features,

    '重要性': rf_model.feature_importances_

}).sort_values('重要性', ascending=False)

print("\n随机森林特征重要性:")

print(rf_feature_importance)

3. 模型对比可视化

# 模型对比

models_comparison = pd.DataFrame({

    '模型': ['线性回归', '随机森林'],

    'MSE': [lr_mse, rf_mse],

    'R²': [lr_r2, rf_r2]

})

print("=== 模型性能对比 ===")

print(models_comparison)

# 预测结果可视化

plt.figure(figsize=(12, 5))

# 实际值 vs 预测值散点图

plt.subplot(1, 2, 1)

plt.scatter(y_test, y_pred_lr, alpha=0.5, label='线性回归')

plt.scatter(y_test, y_pred_rf, alpha=0.5, label='随机森林')

plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=2)

plt.xlabel('实际值')

plt.ylabel('预测值')

plt.title('实际值 vs 预测值')

plt.legend()

# 残差图

plt.subplot(1, 2, 2)

residuals_lr = y_test - y_pred_lr

residuals_rf = y_test - y_pred_rf

plt.scatter(y_pred_lr, residuals_lr, alpha=0.5, label='线性回归残差')

plt.scatter(y_pred_rf, residuals_rf, alpha=0.5, label='随机森林残差')

plt.axhline(y=0, color='black', linestyle='--')

plt.xlabel('预测值')

plt.ylabel('残差')

plt.title('残差分析')

plt.legend()

plt.tight_layout()

plt.show()

七、scikit-learn 高级功能

1. 交叉验证

from sklearn.model_selection import cross_val_score

# 使用5折交叉验证评估模型

cv_scores_lr = cross_val_score(lr_model, X_train_scaled, y_train,

                              cv=5, scoring='r2')

cv_scores_rf = cross_val_score(rf_model, X_train, y_train,

                              cv=5, scoring='r2')

print("=== 交叉验证结果 ===")

print(f"线性回归交叉验证R²: {cv_scores_lr.mean():.4f} (+/- {cv_scores_lr.std() * 2:.4f})")

print(f"随机森林交叉验证R²: {cv_scores_rf.mean():.4f} (+/- {cv_scores_rf.std() * 2:.4f})")

2. 超参数调优

由于中文路径,设置指定目录

import os
import tempfile
from joblib import parallel_backend

# 设置一个纯英文路径的临时文件夹(例如 D:/temp_joblib)
# 确保该文件夹已存在,若不存在可先创建
os.environ["JOBLIB_TEMP_FOLDER"] = "D:/temp_joblib"  # 替换为你的纯英文路径

# 可选:验证临时目录是否生效
print("临时文件夹路径:", os.environ.get("JOBLIB_TEMP_FOLDER"))

开始调优

from sklearn.model_selection import GridSearchCV

# 随机森林超参数搜索

param_grid = {

    'n_estimators': [50, 100, 200],

    'max_depth': [5, 10, 15, None],

    'min_samples_split': [2, 5, 10]

}

grid_search = GridSearchCV(

    RandomForestRegressor(random_state=42),

    param_grid,

    cv=5,

    scoring='r2',

    n_jobs=-1

)

grid_search.fit(X_train, y_train)

print("=== 最佳参数 ===")

print(grid_search.best_params_)

print(f"最佳交叉验证分数: {grid_search.best_score_:.4f}")

# 使用最佳参数重新训练

best_rf_model = grid_search.best_estimator_

y_pred_best_rf = best_rf_model.predict(X_test)

best_rf_r2 = r2_score(y_test, y_pred_best_rf)

print(f"调优后测试集R²: {best_rf_r2:.4f}")

八、实验总结与业务洞察

1. 技术总结

通过本实验,我们掌握了以下scikit-learn核心技能:

  • 数据加载与探索:使用pandas加载数据,进行基本统计分析
  • 数据预处理:使用StandardScaler进行特征标准化
  • 模型训练:使用LinearRegression和RandomForestRegressor
  • 模型评估:使用MSE和R²评估回归模型性能
  • 高级功能:交叉验证、网格搜索超参数调优

2. 业务洞察

基于模型分析,我们发现:

  1. 关键影响因素:在线时长和完成订单数是影响司机收入的主要因素
  2. 模型选择:随机森林在该数据集上表现优于线性回归
  3. 优化建议
    • 提高司机在线时长的利用率
    • 优化订单分配策略提高完成订单数
    • 关注行驶里程的效率(单位里程收入)

3. 后续工作建议

  1. 特征工程:尝试创建新特征,如"每小时订单数"、"每公里收入"
  2. 模型扩展:尝试其他回归算法(梯度提升、支持向量机等)
  3. 聚类分析:使用无监督学习对司机进行分类
  4. 异常检测:识别异常工作模式的司机

附录:关键代码片段汇总

本实验所有关键代码已在上文中完整展示,可直接复制使用。建议在实际环境中逐步运行并理解每个步骤的作用。

更多推荐