数据挖掘实战:同一个数据集,Weka、sklearn、PyCaret 准确率差 6%,问题出在哪?

🔑 关键词:数据挖掘,Weka,scikit-learn,PyCaret,特征工程

📖 摘要:一个业余数据挖掘爱好者用 UCI Adult 数据集对比三种工具的真实记录。具体参数、踩坑步骤、以及我发现的‘隐性预处理鸿沟’——预处理比算法选择重要得多。

去年我想转行数据挖掘,拿 UCI 的 Adult 数据集练手。 这个数据集有 48842 条记录,14 个特征,目标是预测年收入是否超过 50K。 我先用 Weka 3.8.6 的图形界面,点几下选了 J48 决策树,10 折交叉验证,准确率 85.3%。 当时觉得数据挖掘挺简单。 后来用 Python 的 scikit-learn,同样的决策树,默认参数,准确率只有 81.2%。 我以为是算法实现差异,调了 max_depth 从 None 到 5,min_samples_split 从 2 到 10,最好也就 84.7%。 差了 3.6 个百分点,这让我很困惑。

图片

后来我发现问题不在算法,在缺失值处理。 Adult 数据集里 workclass、occupation、native-country 有缺失,用 ? 表示。 Weka 的 J48 默认通过 ReplaceMissingValues 过滤器把 ? 当成独立类别或众数填充,而我用 scikit-learn 时直接 fit,报错 ValueError: Input contains NaN。 我改用 SimpleImputer(strategy='most_frequent') 填充,准确率才到 81.2%。 如果直接用 pandas 的 dropna,数据从 48842 降到 45222,准确率反而到 82.1%,但模型泛化变差。 我管这个叫“隐性预处理鸿沟”——工具自带的默认清洗步骤,比算法本身影响更大。

图片

再对比 PyCaret 3.0。 它的 setup() 会自动处理缺失值、类别编码、归一化,默认用 LightGBM。 我跑 compare_models(),它选了 LightGBM,准确率 87.1%,比 Weka 高 1.8%。 但注意:PyCaret 默认做了 10 折交叉验证,还自动做了特征选择? 我手动关掉 normalize=True,准确率没变。 后来我用 sklearn 的 GradientBoostingClassifier,调参 n_estimators=200, learning_rate=0.1, max_depth=3,准确率 86.8%。 所以工具差距没那么大,关键是预处理和模型选择。 但 PyCaret 的自动预处理里,它把 fnlwgt 这个特征做了标准化?其实树模型不需要。 这说明自动工具不一定全对。

图片

我的独立观点:数据挖掘里,大家总在争论 XGBoost 和 LightGBM 谁强,但我的实验里,预处理策略带来的准确率波动有 4-5 个百分点,而算法切换只带来 1-2 个百分点。 Adult 数据集中 >50K 只占 24%,是典型的不平衡。 我用 SMOTE 过采样后,sklearn 的随机森林(n_estimators=100)从 84.9% 提升到 86.7%,但召回率从 0.62 提到 0.78,精确率从 0.79 降到 0.71。 没有免费午餐。 我建议先花 70% 时间在数据清洗和特征工程上,再花 30% 调参。 这个比例是我踩坑后的经验。

图片

给新手的步骤:别急着上深度学习。

  1. 用 pandas 的 df.isnull().sum() 看缺失值,Adult 里有 3 列有 ?,共 4262 个缺失。
  2. 类别特征用 pd.get_dummies 或 OneHotEncoder,但 native-country 有 41 个类别,独热后维度爆炸到 100+。 我用目标编码替代,准确率升了 0.5%。
  3. 用 imblearn 的 SMOTE 处理不平衡,但记得只在训练集上做。
  4. 对比至少 3 个模型,用交叉验证。 我最后用的 LightGBM + 目标编码 + SMOTE,测试集准确率 87.3%,AUC 0.91。 这个数字在 Kaggle 上不算高,但对我来说够了。 记住:数据挖掘不是刷分,是理解数据生成过程。

图片

🏷️ 标签: