如何基于Pclass与Title从另一DataFrame填充Pandas的Age缺失值?
解决泰坦尼克号数据集Age列缺失值填充问题
首先,你的嵌套循环代码没生效的核心原因是链式索引赋值的陷阱:当你写df.loc[...]['Age']时,Pandas返回的是原DataFrame的一个副本,你对这个副本的修改不会同步到原df中,所以NaN值始终没被覆盖。而且嵌套循环确实不是最优解,尤其是数据集较大时,我们可以用Pandas的原生向量操作来更高效地完成填充。
1. 先修正你的循环代码(快速修复)
只需要把列名直接放到loc的第二个参数里,避免链式索引,就能确保修改作用于原DataFrame:
import pandas as pd # 修正后的循环代码 for tit in df['Title'].unique(): for cls in [1,2,3]: # 直接在loc中指定'Age'列,确保修改原DataFrame df.loc[df['Age'].isna() & (df['Title'] == tit) & (df['Pclass'] == cls), 'Age'] = age_df.loc[tit][cls]
2. 更高效的非循环方法(推荐)
下面几种方法不需要循环,利用Pandas的向量化操作,效率更高,代码也更简洁:
方法一:使用apply逐行匹配填充
定义一个函数,根据每行的Title和Pclass从age_df中获取对应年龄,然后用apply批量处理:
def fill_missing_age(row): if pd.isna(row['Age']): # 根据Title和Pclass从age_df中取对应值 return age_df.loc[row['Title']][row['Pclass']] else: return row['Age'] # 应用函数填充Age列 df['Age'] = df.apply(fill_missing_age, axis=1)
方法二:构建多级索引映射(更高效)
把age_df转换为多级索引的Series,然后通过元组匹配快速填充:
# 将age_df转换为(Title, Pclass)为索引的Series age_mapping = age_df.stack() # 对Age的缺失值,用Title和Pclass的元组去匹配映射值 df['Age'] = df['Age'].fillna( df.apply(lambda x: age_mapping.get((x['Title'], str(x['Pclass']))), axis=1) )
注意:这里
x['Pclass']转成字符串是因为age_df的列名是字符串类型(比如'1','2','3'),如果你的age_df列名是整数,就不需要转换。
方法三:用合并(Merge)的方式填充
把age_df转成长格式,然后和原df合并,再填充缺失值:
# 将age_df转换为长格式:Title、Pclass、FillAge三列 age_df_long = age_df.reset_index().melt( id_vars='index', var_name='Pclass', value_name='FillAge' ).rename(columns={'index': 'Title'}) # 把Pclass转为整数类型,和原df的Pclass类型匹配 age_df_long['Pclass'] = age_df_long['Pclass'].astype(int) # 合并原df和age_df_long,匹配Title和Pclass df = df.merge(age_df_long, on=['Title', 'Pclass'], how='left') # 用FillAge填充Age的缺失值,然后删除临时列 df['Age'] = df['Age'].fillna(df['FillAge']) df.drop('FillAge', axis=1, inplace=True)
总结
如果数据集不大,修正后的循环也能工作,但更推荐后面的非循环方法——Pandas的向量化操作比Python循环快得多,尤其是处理大型数据集时,代码也更符合Pandas的惯用写法。
内容的提问来源于stack exchange,提问作者Fabio Regis
相关产品推荐
相关产品推荐

