如何在Pandas数据框指定列中尽可能上移值?分组匹配问题
问题:DataFrame按class/id分组并匹配对应name值
原始数据
import pandas as pd df = pd.DataFrame({'class': ['class_a', 'class_a', 'class_a', 'class_a', 'class_b', 'class_b', 'class_c', 'class_c', 'class_d'], 'id': ['id1', 'id2', 'id3', '', '', 'id4', 'id5', '', 'id6'], 'name': ['abc1', '', '', 'abc2', 'abc3', '', '', 'abc4', 'abc5']}) print(df)
输出:
class id name 0 class_a id1 abc1 1 class_a id2 2 class_a id3 3 class_a abc2 4 class_b abc3 5 class_b id4 6 class_c id5 7 class_c abc4 8 class_d id6 abc5
期望输出
class id name 0 class_a id1 abc1 1 class_a id2 abc2 2 class_a id3 3 class_b id4 abc3 4 class_c id5 abc4 5 class_d id6 abc5
尝试的错误代码及结果
import numpy as np df.replace('', np.nan, inplace=True) result = df.groupby(['class', 'id'], as_index=False, sort=False).first() print(result)
输出:
class id name 0 class_a id1 abc1 1 class_a id2 None 2 class_a id3 None 3 class_b id4 None 4 class_c id5 None 5 class_d id6 abc5
错误原因
- 分组逻辑错误:用
['class', 'id']分组时,原始数据中空id的行(转成NaN后)会被当成独立分组,但需求是将同class下的非空id和后续的非空name配对,而非空id和对应name不在同一个分组里,自然无法匹配。 - 聚合方法不适用:
groupby.first()仅提取每个分组内的第一个非空值,但name值和对应的id行是分离的,不在同一分组,所以无法把后面的name值关联到前面的id行。
解决方法
方法一:分组填充后筛选
核心思路是按class分组,将name值向前填充到同class下前面空name的id行,再筛选出非空id的行:
import pandas as pd import numpy as np df = pd.DataFrame({'class': ['class_a', 'class_a', 'class_a', 'class_a', 'class_b', 'class_b', 'class_c', 'class_c', 'class_d'], 'id': ['id1', 'id2', 'id3', '', '', 'id4', 'id5', '', 'id6'], 'name': ['abc1', '', '', 'abc2', 'abc3', '', '', 'abc4', 'abc5']}) # 空字符串转NaN df = df.replace('', np.nan) # 按class分组,对name列向前填充,把后续的name补到前面空值位置 df['name'] = df.groupby('class')['name'].ffill() # 筛选非空id的行,去重后重置索引 result = df.dropna(subset=['id']).drop_duplicates(subset=['class', 'id'], keep='first').reset_index(drop=True) print(result)
方法二:分组后手动配对
核心思路是按class提取非空id和name列表,按顺序配对,不足的补NaN:
import pandas as pd import numpy as np df = pd.DataFrame({'class': ['class_a', 'class_a', 'class_a', 'class_a', 'class_b', 'class_b', 'class_c', 'class_c', 'class_d'], 'id': ['id1', 'id2', 'id3', '', '', 'id4', 'id5', '', 'id6'], 'name': ['abc1', '', '', 'abc2', 'abc3', '', '', 'abc4', 'abc5']}) df = df.replace('', np.nan) def process_group(group): # 提取分组内非空的id和name列表 valid_ids = group['id'].dropna().tolist() valid_names = group['name'].dropna().tolist() # 按顺序配对,name数量不足时补NaN paired_names = valid_names + [np.nan] * (len(valid_ids) - len(valid_names)) return pd.DataFrame({ 'class': [group.name] * len(valid_ids), 'id': valid_ids, 'name': paired_names }) # 分组处理后合并结果 result = df.groupby('class', group_keys=False).apply(process_group).reset_index(drop=True) print(result)
两种方法输出均与期望结果一致。
内容的提问来源于stack exchange,提问作者VERBOSE
相关产品推荐
相关产品推荐

