Pandas:按年份分组用列最小值填充数值列空值问题排查
问题原因分析
- 代码不生效的核心原因:
test_df[test_df['year'] == year]返回的是原DataFrame的副本而非视图,对副本执行inplace=True的填充操作,只会修改临时副本,完全不会影响原DataFrametest_df。
正确实现方案
推荐使用groupby+transform的向量化操作方式,无需循环,效率更高且更符合pandas的使用习惯:
import pandas as pd import numpy as np # 测试数据 test_df = pd.DataFrame( data={ 'name': ['institute_1', 'institute_2', 'institute_2', 'institute_1', 'institute_2'], 'score_1': [0.21, np.nan, 0.5, 0.3, np.nan], 'score_2': [np.nan, 0.38, 0.53, 0.3, 0.986], 'year': [2017, 2017, 2018, 2018, 2019] }, columns=['name', 'score_1', 'score_2', 'year'] ) # 筛选需要处理的数值列(排除year列) numeric_cols = [col for col in test_df.select_dtypes(include=['number']).columns if col != 'year'] # 按年份分组,用组内最小值填充对应列的空值 test_df[numeric_cols] = test_df.groupby('year')[numeric_cols].transform( lambda x: x.fillna(x.min()) ) print(test_df)
代码说明
- 精准筛选数值列,避免对
year列执行不必要的操作; groupby('year')按年份分组,transform保证返回结果的索引与原DataFrame一致,可直接赋值覆盖原列;- 对每个分组内的列,用
x.fillna(x.min())完成空值填充逻辑。
循环方式的修正版本
如果一定要用循环实现,需通过索引直接定位原DataFrame的行进行修改,而非操作副本:
import pandas as pd import numpy as np test_df = pd.DataFrame( data={ 'name': ['institute_1', 'institute_2', 'institute_2', 'institute_1', 'institute_2'], 'score_1': [0.21, np.nan, 0.5, 0.3, np.nan], 'score_2': [np.nan, 0.38, 0.53, 0.3, 0.986], 'year': [2017, 2017, 2018, 2018, 2019] }, columns=['name', 'score_1', 'score_2', 'year'] ) numeric_columns = [col for col in test_df.select_dtypes(include=['number']).columns if col != 'year'] for year in range(2017, 2020): # 获取当前年份的行掩码 year_mask = test_df['year'] == year # 计算当前年份各数值列的最小值 min_vals = test_df[year_mask][numeric_columns].min() # 通过loc索引直接修改原DataFrame的对应行和列 test_df.loc[year_mask, numeric_columns] = test_df.loc[year_mask, numeric_columns].fillna(min_vals) print(test_df)
内容的提问来源于stack exchange,提问作者Curious
相关产品推荐
相关产品推荐

