基于最近日期且时差1年内填充DataFrame中的NaN值
问题描述
现有如下DataFrame:
name score date 0 Alice 22.0 2020-12-31 15 Alice 4.0 2005-12-31 5 Alice 1.0 2003-12-31 10 Alice NaN 2000-12-31 6 Bob 8.0 2001-11-02 16 Bob 1.0 2004-11-02 11 Bob 5.0 2003-11-02 1 Bob 45.0 1980-11-02 12 Chuck 9.0 2003-12-03 2 Chuck 4.0 2015-12-03 7 Chuck 9.0 2001-12-03 17 Chuck 2.0 2004-12-03 18 Daren 3.0 2004-03-13 21 Daren 89.0 2015-08-13 3 Daren NaN 2015-03-13 20 Daren 12.0 2015-05-13 8 Daren 5.0 2015-03-17 13 Daren 93.0 2003-03-13 14 Elisa 11.0 2003-01-24 9 Elisa 19.0 2001-01-24 19 Elisa 23.0 2004-01-24 4 Elisa 16.0 2010-01-24
其中部分score值为NaN,需按以下规则替换:
- 对每个
NaN,在同一name分组下,找到与该NaN对应date时间差最小且时间差在1年(365天)内的非NaNscore值进行填充 - 若同一
name下没有符合时间条件的非NaN值,则保留NaN
示例:Daren的NaN会被替换为5,Alice的NaN保留。
重现该DataFrame的代码如下:
import numpy as np import pandas as pd import datetime data = {"name": ['Alice', 'Bob', 'Chuck', 'Daren', 'Elisa', 'Alice', 'Bob', 'Chuck', 'Daren', 'Elisa','Alice', 'Bob', 'Chuck', 'Daren', 'Elisa','Alice', 'Bob', 'Chuck', 'Daren', 'Elisa','Daren','Daren'], "score": [22,45,4,np.nan,16,1,8,9,5,19,np.nan,5,9,93,11,4,1,2,3,23,12,89], "date": ['31/12/2020','11/02/1980','12/03/2015','13/03/2015','24/01/2010','31/12/2003','11/02/2001','12/03/2001','17/03/2015','24/01/2001','31/12/2000','11/02/2003','12/03/2003','13/03/2003','24/01/2003','31/12/2005','11/02/2004','12/03/2004','13/03/2004','24/01/2004','13/05/2015','13/08/2015']} df = pd.DataFrame(data = data) df['date'] = pd.to_datetime(df['date']) df.sort_values(by='name')
解决方案
通过分组遍历缺失值,筛选同组内符合时间条件的记录并取最近时间对应的score填充,代码如下:
def fill_missing_score(group): # 遍历当前分组内所有score为NaN的行 for idx, row in group[group['score'].isna()].iterrows(): target_date = row['date'] # 筛选同组内score非空且时间差在365天内的候选记录 candidates = group[(group['score'].notna()) & ((group['date'] - target_date).abs() <= pd.Timedelta(days=365))] if not candidates.empty: # 计算时间差绝对值,找到最近时间对应的score candidates['time_diff'] = (candidates['date'] - target_date).abs() closest_score = candidates.loc[candidates['time_diff'].idxmin(), 'score'] group.loc[idx, 'score'] = closest_score return group # 按name分组处理后重置索引 filled_df = df.groupby('name').apply(fill_missing_score).reset_index(drop=True) print(filled_df)
结果验证:
- Daren的NaN(对应
date2015-03-13)会匹配到同组内2015-03-17的score=5,时间差4天符合条件,填充为5 - Alice的NaN(对应
date2000-12-31)同组内最近记录的时间差超过365天,保留NaN
内容的提问来源于stack exchange,提问作者You_Donut
相关产品推荐
相关产品推荐

