泰坦尼克号数据集按条件用众数填充Age列缺失值的方法问题排查
问题分析与解决方案:Titanic数据集按Sex和Pclass填充Age缺失值
我来帮你拆解这三种方法遇到的问题,以及对应的修复方案:
一、SimpleImputer方法失效的原因
你遇到的问题主要有两个:
- 未正确将处理结果赋值回原DataFrame:
fit_transform仅返回处理后的数组,但你没有把这个结果映射到原数据的对应缺失位置。 - 索引条件逻辑错误:赋值代码里的
(df.Age.isnull()) & (df.Age[(df['Sex'] == 0) & (df['Pclass'] == 1)])逻辑混乱,后者返回的是一个Series,和df.Age.isnull()做与运算会导致索引不匹配,无法精准定位需要填充的行。
修复后的代码:
from sklearn.impute import SimpleImputer import numpy as np # 定义需要填充的子集条件:性别0、舱位1且Age缺失 fill_condition = (df['Sex'] == 0) & (df['Pclass'] == 1) & (df['Age'].isnull()) # 提取该子集的Age列(转为DataFrame适配SimpleImputer的2D输入要求) age_subset = df.loc[fill_condition, ['Age']] # 初始化并拟合填充器 imputer = SimpleImputer(missing_values=np.nan, strategy='most_frequent') # 填充后将结果赋值回原DataFrame df.loc[fill_condition, 'Age'] = imputer.fit_transform(age_subset).flatten()
二、fillna()方法失效的原因
这个方法的核心问题是链式索引导致的副本修改:
df.loc[(df['Sex'] == 0) & (df['Pclass'] == 1), 'Age'].fillna(...)这种链式索引(先loc再取'Age')大概率返回的是原DataFrame的副本而非视图,此时用inplace=True只会修改副本,原数据完全不受影响。- 另外,
df.Age[(df['Sex'] == 0) & (df['Pclass'] == 1)].mode()返回的是一个Series(可能包含多个众数),直接用int()转换会报错,应该取第一个众数.mode()[0]。
修复后的代码:
# 先计算目标子集的Age众数 mode_age = df.loc[(df['Sex'] == 0) & (df['Pclass'] == 1), 'Age'].mode()[0] # 直接定位原DataFrame的缺失行赋值,避免链式索引 df.loc[(df['Sex'] == 0) & (df['Pclass'] == 1) & (df['Age'].isnull()), 'Age'] = mode_age
三、单独执行有效但循环报错的原因
循环里的问题集中在变量名、循环范围和索引逻辑上:
- 变量名拼写错误:你定义了
indices但赋值时用了未定义的ind,直接触发NameError。 - 循环范围不匹配:
range(1,3)生成的是1和2,但你之前的代码用df['Sex'] == 0,说明Sex的取值是0和1,循环应该写成range(0,2)才能覆盖所有性别类别。 - 索引获取逻辑错误:
df.loc[(df.Sex == i) & (df.Pclass == j), 'Age'].isnull().index返回的是该子集中所有行的索引(包括非缺失行),而非仅缺失值的索引,正确做法是直接筛选同时满足性别、舱位、Age缺失的行。 - mode()处理不当:和第二种方法一样,
mode()返回Series,必须取第一个值.mode()[0],否则多众数场景下int()转换会失败。
修复后的循环代码:
for sex_val in range(0, 2): # 覆盖Sex的0、1两个取值 for pclass_val in range(1, 4): # 覆盖Pclass的1-3三个取值 # 精准筛选需要填充的行 fill_condition = (df['Sex'] == sex_val) & (df['Pclass'] == pclass_val) & (df['Age'].isnull()) if not df.loc[fill_condition].empty: # 跳过空子集避免报错 mode_age = df.loc[(df['Sex'] == sex_val) & (df['Pclass'] == pclass_val), 'Age'].mode()[0] df.loc[fill_condition, 'Age'] = mode_age # 验证填充结果 for sex_val in range(0,2): for pclass_val in range(1,4): missing_count = df.loc[(df['Sex'] == sex_val) & (df['Pclass'] == pclass_val), 'Age'].isnull().sum() print(f"Sex={sex_val}, Pclass={pclass_val} 缺失值数量: {missing_count}")
内容的提问来源于stack exchange,提问作者Abdelrahman Abozied
相关产品推荐
相关产品推荐

