数学建模竞赛实战:基于熵权法与随机森林的用户体验影响因素分析
1. 项目概述:从赛题到实战的完整拆解
“北京移动用户体验影响因素研究”,这个题目一出来,很多初次接触数学建模,特别是大数据赛道的同学可能会有点懵。这听起来像是一个市场调研或者用户行为分析的课题,怎么就成了数学建模竞赛题?这正是MathorCup这类竞赛的魅力所在——它要求你不仅仅会解数学题,更要能将现实世界中模糊、复杂的商业问题,转化为清晰、可计算的数学模型,并用数据和代码去验证你的想法。简单来说,这道题的核心就是:给你一堆北京移动用户的上网行为、通话记录、地理位置等大数据,让你像个侦探一样,从海量数据中找出究竟是哪些因素在“搞鬼”,影响了用户对移动网络服务的整体感受(也就是用户体验)。
这绝对不是一个拍脑袋就能回答的问题。用户体验是一个综合性的主观感受,它可能和你的手机信号满不满格有关,也可能和你刷视频时卡不卡顿有关,甚至和你在不同区域(比如市中心和郊区)的网络覆盖差异有关。我们的任务,就是通过数学和计算机的力量,把这些潜在的影响因素一个个揪出来,量化它们的影响程度,并建立预测模型。这整个过程,就是“建模”。而“代码实现”,则是将我们头脑中的数学模型和算法思路,变成计算机可以理解和执行的指令,让机器代替我们去处理那可能高达TB级别的数据,并给出科学的结论。对于参赛者而言,这不仅考验数学功底和编程能力,更考验对业务的理解、对数据的敏感度以及将复杂问题体系化的逻辑思维。
2. 问题一核心需求与解题思路解析
通常,这类赛题的问题一会是整个项目的基石,它要求我们完成最基础的探索性工作。根据过往赛题经验(如2022年MathorCup B题),问题一极有可能要求我们 构建用户体验的综合评价指标体系 ,并 对原始数据进行预处理和初步分析 。为什么这是第一步?因为在你研究“什么因素影响体验”之前,你必须先定义清楚什么叫“好的体验”。你不能直接用“用户投诉量”或者“客服打分”这种单一指标,因为太片面了。我们需要一个能综合反映网络质量、服务稳定性和用户感知的“用户体验分数”。
2.1 构建综合评价指标体系
这是一个多指标决策问题。我们需要的不是一个指标,而是一套指标“组合拳”。这套体系通常需要涵盖以下几个维度:
-
网络性能维度 :这是体验的物理基础。包括:
- 速率类指标 :平均下载速率、平均上传速率、速率稳定性(方差)。
- 时延类指标 :网络时延(Ping值)、交互时延。
- 可靠性指标 :网络可用率(信号强度大于阈值的时长占比)、掉线率、切换成功率(从一个基站切换到另一个基站的成功概率)。
-
业务质量维度 :用户具体在用什么业务,体验如何?
- 网页浏览 :页面首屏加载时间、完整加载成功率。
- 视频播放 :视频卡顿次数、卡顿时长占比、初始缓冲时间。
- 游戏 :游戏时延、抖动(时延的变化率)、丢包率。
- 语音通话 :语音接通率、通话掉话率、语音质量评分(MOS分)。
-
用户行为与感知维度 :数据背后反映的用户态度。
- 投诉数据 :用户主动投诉的次数、投诉类型。
- APP使用粘性 :在网时长、流量使用习惯、高价值业务使用频率。
- 区域对比 :用户在不同时间(忙时/闲时)、不同地点(商圈/住宅/地铁)的体验差异。
构建好这套指标后,我们面临下一个问题:如何把这些单位不同、量纲各异的指标融合成一个总分?这里就需要引入 综合评价模型 。常见的方法有熵权法、主成分分析法(PCA)和层次分析法(AHP)。
- 熵权法 :这是一种客观赋权法。它的核心思想是:如果一个指标的数值在不同样本间差异越大(即信息熵越小),说明这个指标在区分用户体验好坏方面越有效,就应该赋予更大的权重。这种方法完全由数据本身驱动,避免了主观偏见,非常适合大数据场景下的初步权重确定。
- 主成分分析法(PCA) :当我们的指标数量很多,且可能存在相关性(比如下载速率和视频卡顿率高度相关)时,PCA可以将这些相关的指标转换为一组不相关的新指标(主成分),用少数几个主成分就能解释大部分原始数据的信息。我们可以用第一主成分的得分作为用户体验的综合得分。
- 层次分析法(AHP) :这是一种主观赋权法,需要专家对指标的重要性进行两两比较打分。在竞赛中,如果缺乏专家资源,可以谨慎参考行业标准或文献来构建判断矩阵。AHP更适合与熵权法结合,形成主客观结合的权重。
实操心得 :在有限时间的竞赛中, 推荐优先使用熵权法 。因为它实现简单,结果客观,代码成熟。我们可以先用电权法算出客观权重,如果时间充裕,可以再用AHP的结论进行微调或对比分析,作为模型稳健性的一个验证点,这往往是论文的加分项。
2.2 数据预处理的核心步骤
大赛提供的数据通常是原始、杂乱且庞大的。直接建模等于“垃圾进,垃圾出”。预处理是关键,通常占整个数据分析工作量的60%以上。
-
数据清洗 :
- 处理缺失值 :对于网络指标(如速率、时延)的缺失,若比例较小(<5%),可采用前后时刻均值或线性插值填充;若比例大,或与业务强相关(如掉话记录),则考虑将整条记录标记或分箱处理,不宜简单填充。
- 处理异常值 :利用箱线图或3σ原则识别异常值。对于明显不合理的记录(如下载速率为负数或极大值),需要探究原因:是测量错误、测试数据,还是特殊用户(如热点用户)?根据情况决定是剔除、修正还是保留。
- 格式统一 :将时间字段统一为
datetime格式,区域编码、业务类型等分类变量统一为字符串或整数编码。
-
数据集成与规约 :
- 多表关联 :用户基础信息表、网络信令数据表、业务日志表、地理位置信息表需要通过共同的键(如用户匿名ID、时间戳、基站ID)进行关联,形成一张宽表。
- 数据聚合 :原始数据可能是秒级或分钟级的流水记录。我们需要将其聚合到 以用户-时间窗口(如每天) 为单位的分析粒度。例如,计算用户A在2022年10月1日这天的平均下载速率、总流量、视频卡顿总时长等。
-
特征工程 :
- 衍生特征 :这是提升模型效果的关键。例如,从“下载速率”可以衍生出“忙闲时速率比”(忙时速率/闲时速率),反映网络拥塞对用户的影响;从“位置序列”可以衍生出“常驻区域类型”(家、公司、通勤路上)、“移动范围”等。
- 特征缩放 :由于后续很多模型(如回归、聚类)对量纲敏感,需要对连续数值特征进行标准化(Z-score)或归一化(Min-Max)。
# 示例:使用pandas进行数据预处理的代码片段
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
# 1. 读取数据
df = pd.read_csv('user_network_data.csv')
# 2. 处理缺失值 - 对于数值列,用中位数填充
numeric_cols = ['download_speed', 'upload_speed', 'latency']
for col in numeric_cols:
df[col].fillna(df[col].median(), inplace=True)
# 3. 处理异常值 - 使用箱线图原则,将超出1.5倍IQR的值用上下限替换
def cap_outliers(series):
Q1 = series.quantile(0.25)
Q3 = series.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
return series.clip(lower_bound, upper_bound)
df[numeric_cols] = df[numeric_cols].apply(cap_outliers)
# 4. 创建时间特征
df['timestamp'] = pd.to_datetime(df['timestamp'])
df['hour'] = df['timestamp'].dt.hour
df['is_busy_hour'] = df['hour'].apply(lambda x: 1 if (x>=9 and x<=11) or (x>=19 and x<=21) else 0)
# 5. 数据聚合:按用户和天聚合,计算日均指标
df['date'] = df['timestamp'].dt.date
daily_agg = df.groupby(['user_id', 'date']).agg({
'download_speed': 'mean',
'latency': 'mean',
'data_usage': 'sum'
}).reset_index()
# 6. 特征缩放
scaler = StandardScaler()
scaled_features = scaler.fit_transform(daily_agg[['download_speed', 'latency']])
daily_agg[['download_speed_scaled', 'latency_scaled']] = scaled_features
3. 建模方案详解:从指标体系到影响因素挖掘
在完成了数据预处理和综合评价体系构建后,我们得到了每个用户在每个时间片段的“用户体验综合得分”。现在,问题一的核心任务就变成了: 寻找哪些因素与这个综合得分显著相关,并尝试建立预测或解释模型 。这本质上是一个 回归分析 或 特征重要性分析 问题。
3.1 模型选择与原理
我们面对的是高维、可能具有复杂非线性关系的数据。因此,不宜直接使用简单的线性回归。以下是几种非常适合此场景的模型:
-
随机森林回归(Random Forest Regressor) :
- 为什么选它 :随机森林是集成学习算法,通过构建多棵决策树并综合其结果,能有效防止过拟合,对数据中的非线性关系和交互作用捕捉能力强。最重要的是,它内置了 特征重要性评估 功能,可以直接输出每个特征(如下载速率、所在区域、时间等)对于预测用户体验得分的贡献度,这完美契合“影响因素研究”的目标。
- 工作原理 :通过Bootstrap抽样生成多个训练子集,为每个子集训练一棵决策树。在树的每个节点分裂时,随机选取部分特征寻找最佳分裂点。最终预测结果是所有树预测值的平均。特征重要性通常通过计算该特征在所有树上带来的不纯度减少的平均值来衡量。
-
梯度提升树(如XGBoost, LightGBM) :
- 为什么选它 :这是比随机森林更强大的集成算法,尤其是LightGBM,在处理大数据时速度极快,精度也往往更高。它同样提供特征重要性评估。XGBoost和LightGBM通过梯度提升框架,以迭代的方式构建树,每一棵树都学习之前所有树组合的残差,从而获得更强的预测能力。
- 如何选择 :如果数据量特别大(百万行以上), 优先使用LightGBM ,因为它采用了直方图算法和带深度限制的Leaf-wise生长策略,训练效率极高。XGBoost则更稳健,调参空间丰富,在中等规模数据上表现优异。
-
线性模型 + 正则化(Lasso回归) :
- 为什么选它 :如果怀疑影响因素很多,但真正起主导作用的只有少数几个,Lasso回归就非常有用。它在损失函数中加入L1正则化项,可以将不重要特征的系数压缩至0,从而实现 特征选择 。它的结果比树模型更容易解释,我们可以直接得到如“下载速率每提升1Mbps,体验得分增加0.5分”这样的明确结论。
- 局限性 :它假设特征与目标变量是线性关系,无法捕捉复杂的非线性交互。因此,常作为基线模型或与树模型结果对照使用。
3.2 模型实现与特征重要性分析
我们以随机森林为例,展示核心代码实现和结果分析流程。
# 示例:使用Scikit-learn实现随机森林回归与特征重要性分析
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
import seaborn as sns
# 假设 df 是经过预处理和聚合后的数据集,包含特征X和用户体验综合得分y
# X 包含:下载速率、上传速率、时延、丢包率、所在区域类型编码、是否忙时、日均流量等特征
# y 是之前通过熵权法计算出的用户体验综合得分
X = df.drop(['user_experience_score', 'user_id', 'date'], axis=1) # 移除目标列和ID列
y = df['user_experience_score']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 初始化随机森林回归模型
# 关键参数说明:
# n_estimators: 树的数量,通常越大越好,但计算成本增加,一般100-500
# max_depth: 树的最大深度,控制模型复杂度,防止过拟合,可以用网格搜索调优
# random_state: 随机种子,保证结果可复现
rf_model = RandomForestRegressor(n_estimators=200, max_depth=10, random_state=42, n_jobs=-1)
# 训练模型
rf_model.fit(X_train, y_train)
# 在测试集上预测
y_pred = rf_model.predict(X_test)
# 评估模型性能
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f"测试集均方误差(MSE): {mse:.4f}")
print(f"测试集决定系数(R2 Score): {r2:.4f}")
# --- 核心部分:特征重要性分析 ---
# 获取特征重要性
importances = rf_model.feature_importances_
feature_names = X.columns
indices = np.argsort(importances)[::-1] # 按重要性降序排列
# 打印最重要的10个特征
print("\n特征重要性排名(Top 10):")
for i in range(min(10, len(indices))):
print(f"{i+1}. {feature_names[indices[i]]}: {importances[indices[i]]:.4f}")
# 可视化特征重要性
plt.figure(figsize=(12, 6))
plt.title("随机森林模型 - 特征重要性")
plt.bar(range(X.shape[1]), importances[indices], align='center')
plt.xticks(range(X.shape[1]), [feature_names[i] for i in indices], rotation=90)
plt.tight_layout()
plt.show()
# 进一步分析:使用排列重要性(Permutation Importance)进行验证
# 排列重要性更稳健,它打乱某个特征的值,看模型性能下降多少,下降越多说明该特征越重要
from sklearn.inspection import permutation_importance
result = permutation_importance(rf_model, X_test, y_test, n_repeats=10, random_state=42, n_jobs=-1)
sorted_idx = result.importances_mean.argsort()[::-1]
plt.figure(figsize=(12, 6))
plt.boxplot(result.importances[sorted_idx].T, vert=False,
labels=[feature_names[i] for i in sorted_idx])
plt.title("排列重要性 (Permutation Importance)")
plt.tight_layout()
plt.show()
通过运行上述代码,我们可以得到两份重要性排名:一份是基于Gini不纯度的内置重要性,一份是更稳健的排列重要性。对比两者,如果某个特征(例如“忙时平均下载速率”)在两个榜单上都名列前茅,那么它就是影响用户体验的 关键确定性因素 。
3.3 结果解读与业务洞察
模型输出的不仅仅是冷冰冰的排名,我们需要将其转化为有业务意义的结论。例如,分析结果可能显示:
- 网络性能是基石 :“下载速率”和“网络时延”的重要性得分最高,这与常识相符。但我们可以进一步细化: “忙时下载速率”的重要性远高于“全天平均下载速率” ,这说明用户对网络拥塞时期的体验更为敏感,网络建设的重点应放在扩容高峰时段容量上。
- 业务体验差异大 :“视频卡顿率”的重要性高于“网页加载失败率”。这意味着在当前以视频为主导的流量消费模式下,保障视频流畅播放对提升整体体验至关重要。
- 区域因素显著 :“所在区域类型(如商圈、地铁)”是一个重要特征。模型可能揭示出地铁站内的网络体验显著差于地面商圈,这为网络优化提供了明确的重点区域。
- 用户行为的影响 :“用户月均流量”也可能是一个重要特征。高流量用户(可能是重度视频或游戏用户)对网络质量的变化更敏感,体验得分波动更大。
注意事项 :特征重要性高,只代表该特征与目标变量(体验得分)在模型视角下关联性强, 不等于因果关系 。例如,“用户使用某款视频APP的时长”重要性高,可能是因为这款APP对网络要求高,也可能是因为这款APP本身体验好吸引了用户长时间使用。需要结合业务知识进行解读,避免得出错误结论。
4. 代码实现全流程与工程化要点
对于数学建模竞赛,代码不仅仅是实现算法的工具,更是你思路清晰、工作严谨的体现。一个工程化、可复现的代码结构能极大提升工作效率和论文质量。
4.1 项目目录结构与模块化设计
不建议将所有代码写在一个Jupyter Notebook或一个Python文件里。推荐如下目录结构:
beijing_mobile_analysis/
│
├── data/ # 存放数据
│ ├── raw/ # 原始数据(不要动)
│ ├── processed/ # 处理后的中间数据
│ └── final/ # 最终用于建模的数据
│
├── src/ # 源代码
│ ├── data_preprocessing.py # 数据清洗、集成、特征工程
│ ├── evaluation_model.py # 综合评价模型(熵权法/PCA)
│ ├── factor_analysis.py # 影响因素分析模型(随机森林/XGBoost)
│ ├── utils.py # 工具函数(如绘图配置、日志记录)
│ └── config.py # 配置文件(路径、参数常量)
│
├── notebooks/ # Jupyter Notebook用于探索性分析
│ └── 01_eda.ipynb # 探索性数据分析
│
├── models/ # 保存训练好的模型文件(.pkl)
├── results/ # 保存输出结果(图表、重要性排名CSV)
├── requirements.txt # 项目依赖包列表
└── main.py # 主程序,串联整个流程
在 config.py 中定义全局变量,避免硬编码:
# config.py
DATA_RAW_PATH = './data/raw/network_logs.csv'
DATA_PROCESSED_PATH = './data/processed/daily_features.csv'
MODEL_SAVE_PATH = './models/rf_model.pkl'
RANDOM_STATE = 42
TEST_SIZE = 0.2
4.2 核心模块代码示例
1. 数据预处理模块 ( data_preprocessing.py )
import pandas as pd
import numpy as np
from config import DATA_RAW_PATH, DATA_PROCESSED_PATH
def load_and_clean_data(filepath):
"""加载并清洗原始数据"""
df = pd.read_csv(filepath)
# ... 具体的清洗逻辑(处理缺失值、异常值、格式转换)
return df_cleaned
def feature_engineering(df):
"""特征工程:创建衍生特征"""
df['speed_ratio_busy_idle'] = df['busy_hour_speed'] / (df['idle_hour_speed'] + 1e-5) # 避免除零
df['area_type'] = df.apply(categorize_area, axis=1) # 根据经纬度判断区域类型
# ... 更多特征
return df
def aggregate_data(df):
"""数据聚合:按用户-天聚合"""
df['date'] = pd.to_datetime(df['timestamp']).dt.date
agg_funcs = {
'download_speed': ['mean', 'std'],
'latency': ['mean', 'max'],
'data_usage': 'sum',
# ...
}
df_daily = df.groupby(['user_id', 'date']).agg(agg_funcs)
df_daily.columns = ['_'.join(col).strip() for col in df_daily.columns.values] # 扁平化列名
return df_daily.reset_index()
if __name__ == '__main__':
raw_df = load_and_clean_data(DATA_RAW_PATH)
featured_df = feature_engineering(raw_df)
final_df = aggregate_data(featured_df)
final_df.to_csv(DATA_PROCESSED_PATH, index=False)
print(f"数据预处理完成,保存至: {DATA_PROCESSED_PATH}")
2. 综合评价模块 ( evaluation_model.py )
import numpy as np
import pandas as pd
def entropy_weight_method(data):
"""
熵权法计算权重
:param data: DataFrame, 行为样本,列为评价指标(所有指标应为正向指标)
:return: weights (array), 各指标权重
"""
# 标准化
data_normalized = data.apply(lambda x: (x - x.min()) / (x.max() - x.min() + 1e-10))
# 计算比重
p = data_normalized.div(data_normalized.sum(axis=0), axis=1)
# 计算熵值
k = 1 / np.log(data.shape[0])
entropy = (-k) * (p * np.log(p + 1e-10)).sum(axis=0) # 加极小值防止log(0)
# 计算差异系数和权重
d = 1 - entropy
weights = d / d.sum()
return weights.values
def calculate_comprehensive_score(data, weights):
"""计算综合得分"""
normalized_data = data.apply(lambda x: (x - x.min()) / (x.max() - x.min() + 1e-10))
score = normalized_data.dot(weights)
return score
# 使用示例
# 假设 indicators_df 包含多个正向化后的指标列
# weights = entropy_weight_method(indicators_df)
# df['experience_score'] = calculate_comprehensive_score(indicators_df, weights)
4.3 模型训练与评估的完整Pipeline
在 main.py 或一个独立的脚本中,将整个流程串联起来:
# main.py
import pandas as pd
from src.data_preprocessing import load_and_clean_data, feature_engineering, aggregate_data
from src.evaluation_model import entropy_weight_method, calculate_comprehensive_score
from src.factor_analysis import train_random_forest, analyze_feature_importance
from config import *
import joblib # 用于保存模型
def main():
print("Step 1: 数据预处理...")
# 调用预处理模块函数
processed_data = aggregate_data(feature_engineering(load_and_clean_data(DATA_RAW_PATH)))
print("Step 2: 构建用户体验综合得分...")
# 选择用于评价的指标列
indicator_cols = ['download_speed_mean', 'latency_mean', 'packet_loss_rate_mean', 'video_stutter_freq']
indicators_df = processed_data[indicator_cols]
weights = entropy_weight_method(indicators_df)
processed_data['exp_score'] = calculate_comprehensive_score(indicators_df, weights)
print("Step 3: 准备建模数据...")
# 选择作为影响因素的候选特征列
feature_cols = [col for col in processed_data.columns if col not in ['user_id', 'date', 'exp_score'] + indicator_cols]
X = processed_data[feature_cols]
y = processed_data['exp_score']
print("Step 4: 训练随机森林模型并分析因素...")
model, X_test, y_test, y_pred, feature_importance_df = train_random_forest(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)
print("Step 5: 保存模型和结果...")
joblib.dump(model, MODEL_SAVE_PATH)
feature_importance_df.to_csv('./results/feature_importance.csv', index=False)
print(f"模型已保存至 {MODEL_SAVE_PATH}")
print(f"特征重要性结果已保存至 ./results/feature_importance.csv")
# 输出模型性能
from sklearn.metrics import r2_score
print(f"\n模型在测试集上的R2分数: {r2_score(y_test, y_pred):.4f}")
print("\nTop 5影响因素:")
print(feature_importance_df.head())
if __name__ == '__main__':
main()
5. 实战避坑指南与常见问题排查
在实际操作中,从数据到结论的路上布满“坑”。以下是我在多次类似项目中总结出的经验,能帮你节省大量调试时间。
5.1 数据层面的典型问题
-
数据规模与内存不足 :
- 问题 :原始数据几个G,用
pandas读入时内存溢出。 - 解决方案 :
- 分块读取 :使用
pandas.read_csv(..., chunksize=50000),逐块处理后再聚合。 - 指定数据类型 :在读取时用
dtype参数指定每列类型,如将int64转为int32,float64转为float32。 - 使用高效工具 :对于超大数据,考虑使用
Dask或Spark进行分布式处理。 - 过滤早期数据 :分析前先过滤掉无关字段,只读取需要的列(
usecols参数)。
- 分块读取 :使用
- 问题 :原始数据几个G,用
-
时间戳处理混乱 :
- 问题 :时间格式不统一(如‘2022-10-01’, ‘2022/10/01 14:30’, 时间戳毫秒数),时区不一致。
- 解决方案 :使用
pd.to_datetime()统一转换,并指定format参数或unit='ms'。务必检查数据是否包含时区信息,如有必要,使用dt.tz_convert统一为北京时间。
-
关联键不唯一或缺失 :
- 问题 :用
user_id和timestamp关联两张表时,发现重复或匹配不上。 - 解决方案 :关联前务必进行数据探查。检查重复值:
df.duplicated(subset=['user_id', 'timestamp']).sum()。对于一对多关联,要明确聚合逻辑(如取平均值、求和)。对于匹配不上的记录,要分析是数据错误还是正常情况(如用户在该时段无记录),决定是内连接(丢弃)还是外连接(保留为NaN后续处理)。
- 问题 :用
5.2 建模与结果分析中的陷阱
-
特征重要性“欺骗”你 :
- 问题 :发现“用户ID”或“日期”这类无意义字段的重要性排名很高。
- 原因与解决 :这通常是 数据泄露 的标志。可能是在特征工程中不小心引入了未来信息(如用全局统计量填充缺失值),或者目标变量信息直接或间接地包含在了特征中。务必确保特征都是基于历史或当前时刻的信息构建的。在划分训练集/测试集 之后 再进行基于训练集的标准化或填充。
-
模型过拟合(R2训练集接近1,测试集很低) :
- 问题 :模型在训练集上表现完美,在测试集上一塌糊涂。
- 解决方案 :
- 增加数据 :如果数据量小,这是首要问题。
- 简化模型 :降低树模型的
max_depth、min_samples_split。 - 交叉验证 :使用
cross_val_score评估模型泛化能力,而不是单次划分。 - 正则化 :对于线性模型,增加L1/L2正则化强度。
- 特征选择 :移除不相关或高度相关的特征。
-
结果不稳定,每次运行排名不同 :
- 问题 :随机森林的特征重要性排名每次都有些许变化。
- 原因与解决 :这是随机性的正常体现。为了得到稳定结论:
- 设置随机种子 :在
RandomForestRegressor(random_state=42)和train_test_split(random_state=42)中固定种子。 - 多次平均 :运行模型多次(如10次),取特征重要性的平均值作为最终排名。
- 使用排列重要性 :排列重要性比内置的基于Gini的重要性更稳定,受随机性影响小。
- 设置随机种子 :在
5.3 性能优化与调试技巧
- 利用
.loc和.iloc避免链式赋值警告 :当需要对DataFrame的某个子集赋值时,使用df.loc[mask, column] = value而不是df[mask][column] = value,后者会产生SettingWithCopyWarning且可能修改失败。 - 使用向量化操作代替循环 :Pandas和NumPy的向量化运算比Python原生循环快成百上千倍。例如,计算一列数据的移动平均,用
df['col'].rolling(window=7).mean()而不是for循环。 - 善用
sklearn的Pipeline :对于复杂的预处理和建模流程,使用Pipeline可以封装步骤,避免数据泄露,并使代码更简洁、易于交叉验证。 - 可视化贯穿始终 :不要只在最后才画图。在数据清洗阶段,用直方图和箱线图看分布和异常值;在特征工程后,用热力图看特征相关性;在模型评估时,用散点图看预测值与真实值的关系。可视化是发现问题和理解结果最直观的工具。
最后,记住数学建模竞赛的核心是 用模型讲一个好故事 。你的代码和算法是工具,最终要服务于一个清晰、有逻辑、有洞察的结论。从“北京移动用户体验影响因素”这个题目出发,你的故事线应该是: 定义体验(综合评价) -> 量化体验(计算得分) -> 探索原因(影响因素分析) -> 提出建议(基于发现的洞察) 。确保你的论文和代码都紧紧围绕这条主线展开,每一个步骤都有理有据,这样才能在比赛中脱颖而出。
更多推荐



所有评论(0)