pandas groupby根据二进制列应用列中的列表

时间:2019-03-11 22:38:47

标签: python pandas pandas-groupby

我有一个数据框:

id  to    from    flag
1    a     x        1
1    a     y        0
2    c     z        1
2    c     m        1
2    b     v        0
2    b     p        0

,并且我想groupby(['id','to'])并返回其中仅带有标志1的元素的列表。如果没有元素具有标志1,则结果输出应为“无”。所需的输出应为:

id  to  from 
 1   a  ['x']  
 2   c  ['z','m'] 
 2   b  None

我可以申请

out_df = df.groupby(['id', 'to'])['from'].apply(
       lambda x: match_to_list(x['from'], x['flag'])).reset_index()

其中:

def match_to_list(to, flag):
    matches = list(to.iloc[flag.nonzero()[0]])
    if len(matches) == 0:
        return 'None'
    else:
        matches

但是这花费了太长时间,我认为必须有一种更好的方法来弥补我的缺失。

任何帮助/见解将不胜感激! TIA

1 个答案:

答案 0 :(得分:0)

IIUC 1st用MultiIndex创建索引,然后我们用groupby进行agg

idx=pd.MultiIndex.from_tuples(list(map(tuple,df[['id','to']].drop_duplicates().values.tolist())))
yourdf=df.loc[df.flag==1].groupby(['id','to'])['from'].agg(list).reindex(idx).reset_index()
yourdf
Out[13]: 
   level_0 level_1    from
0        1       a     [x]
1        2       c  [z, m]
2        2       b     NaN

或者仅使用apply,效率较低但可读性更高

df.groupby(['id','to']).apply(lambda x : x['from'][x['flag']==1].tolist() if (x['flag']==1).any() else None).reset_index()
Out[17]: 
   id to       0
0   1  a     [x]
1   2  b    None
2   2  c  [z, m]