如何处理分类特征smoking_status中的NaN值?
smoking_status缺失值的实用方案 Great question—handling missing categorical data like your smoking_status feature can feel a bit tricky at first, but there are several practical, context-aware approaches to tackle this. Let’s walk through the most common (and effective) options:
添加专属的"Missing"类别
这是最直接且安全的方法,尤其适合当缺失值本身可能隐含某种信息(比如用户不愿透露吸烟状态),或者你不确定缺失的原因时。通过新增一个类别,你不会丢失任何样本,后续模型也能学习这个"缺失"类别和目标变量的关联。
示例代码(用Pandas):import pandas as pd df['smoking_status'] = df['smoking_status'].fillna('Missing')基于关联特征的统计填充(谨慎使用众数)
- 简单众数填充:如果缺失值是完全随机的(MCAR),且某类占比极高(比如80%的样本是"never smoked"),可以用众数填充。但要注意,如果缺失不是随机的(比如年轻人更不愿填写),这种方法会引入偏差。
示例代码:mode_status = df['smoking_status'].mode()[0] df['smoking_status'] = df['smoking_status'].fillna(mode_status) - 分组智能填充:更精准的方式是结合与吸烟状态相关的特征(比如年龄、性别、职业)分组,用每组的众数填充缺失值。比如中老年组的"formerly smoked"占比更高,分组后填充更贴合真实情况。
示例代码:
👉 注意:如果分组后某组样本量极少(比如<10个),这样的众数没有统计意义,建议合并小分组或者 fallback 到全局众数。# 按年龄和性别分组,用每组的众数填充缺失值 df['smoking_status'] = df.groupby(['age', 'gender'])['smoking_status'].transform( lambda x: x.fillna(x.mode()[0]) )
- 简单众数填充:如果缺失值是完全随机的(MCAR),且某类占比极高(比如80%的样本是"never smoked"),可以用众数填充。但要注意,如果缺失不是随机的(比如年轻人更不愿填写),这种方法会引入偏差。
用预测模型填充缺失值
当你有足够多与吸烟状态相关的特征(比如是否有呼吸系统疾病、家族病史、生活地区等),可以训练一个分类模型来预测缺失的smoking_status值。这种方法精度更高,但需要更多的特征工程。
大致步骤示例:from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline # 拆分数据为有缺失和无缺失的子集 df_missing = df[df['smoking_status'].isna()] df_complete = df.dropna(subset=['smoking_status']) # 定义特征和目标变量 X = df_complete.drop('smoking_status', axis=1) y = df_complete['smoking_status'] # 构建预处理管道(处理其他分类/数值特征) preprocessor = ColumnTransformer( transformers=[ ('cat', OneHotEncoder(handle_unknown='ignore'), ['gender', 'occupation']), ('num', 'passthrough', ['age', 'income']) ]) # 训练随机森林分类器 model = Pipeline(steps=[('preprocessor', preprocessor), ('classifier', RandomForestClassifier(n_estimators=100))]) model.fit(X, y) # 预测并填充缺失值 df.loc[df['smoking_status'].isna(), 'smoking_status'] = model.predict(df_missing.drop('smoking_status', axis=1))👉 注意:要避免数据泄漏,比如不要用目标变量相关的特征来训练,同时要对模型进行交叉验证确保稳定性。
删除缺失样本(仅作为最后选项)
只有当缺失样本占比极低(比如<5%),且删除后数据集仍然具有代表性时,才考虑这种方法。如果缺失占比高,删除会大幅减少样本量,导致模型泛化能力下降。
示例代码:df = df.dropna(subset=['smoking_status'])
快速决策指南
- 如果缺失原因不明或缺失本身有意义 → 新增"Missing"类别
- 如果有相关特征且缺失非随机 → 分组填充或模型预测
- 如果缺失完全随机且占比极低 → 众数填充或删除样本
内容的提问来源于stack exchange,提问作者adi_tdkr

