通过使用pandas对列进行分组来汇总数据帧

时间:2017-09-28 08:41:45

标签: python pandas dataframe group-by pandas-groupby

我有一个数据框

id  store  val1    val2
1    abc    20      30
1    abc    20      40
1    qwe    78      45
2    dfd    34      45
2    sad    43      45

从此我必须在id上分组并创建一个新的df,其中包含total_storeunique stores以及non-repeating_stores列,其中包含此类商店出现次数。 我的最终输出应该是

id    total_store    unique stores    non-repeating_stores
1        3              2                   1
2        2              2                   2

我可以通过

获得全部商店
df.groupby('id')['store'].count()

但我如何从中获取其他人并形成数据框

2 个答案:

答案 0 :(得分:2)

您可以使用groupby + agg

df = df.groupby('id').store.agg(['count', 'nunique', \
                lambda x: x.drop_duplicates(keep=False).size])
df.columns = ['total_store', 'unique stores', 'non-repeating_stores']

df    
    total_store  unique stores  non-repeating_stores
id                                                  
1             3              2                     1
2             2              2                     2

对于较旧的pandas版本,传递dict可以简化代码(在0.20及之后弃用):

agg_funcs = {'total_stores' : 'count', 'unique_stores' : 'nunique', 
         'non-repeating_stores' : lambda x: x.drop_duplicates(keep=False).size
}
df = df.groupby('id').store.agg(agg_funcs)

df 
    total_stores  non-repeating_stores  unique_stores
id                                                   
1              3                     1              2
2              2                     2              2

作为速度的轻微改进,您可以使用drop_duplicates'姊妹方法,duplicated,以这种方式,as documented by jezrael

lambda x: (~x.duplicated(keep=False)).sum()

这将替换agg中的第三个函数,对大小为1000000的大数据的速度提升20%:

1 loop, best of 3: 7.31 s per loop 

v / s

1 loop, best of 3: 5.19 s per loop 

答案 1 :(得分:2)

groupbyaggcount一起使用nunique。最后一个函数有点复杂 - 需要使用sum反转duplicated计算所有非dupe:

如果需要计算NaN,请使用size代替count

df = df.groupby('id')['store'].agg(['count', 
                                   'nunique', 
                                    lambda x: (~x.duplicated(keep=False)).sum()])
df.columns = ['total_store', 'unique stores', 'non-repeating_stores']
print (df)
    total_store  unique stores  non-repeating_stores
id                                                  
1             3              2                     1
2             2              2                     2

<强>计时

np.random.seed(123)
N = 1000000


L = np.random.randint(10000,size=N).astype(str)
df = pd.DataFrame({'store': np.random.choice(L, N),
                   'id': np.random.randint(10000, size=N)})
print (df)

In [120]: %timeit (df.groupby('id')['store'].agg(['count',  'nunique', lambda x: (~x.duplicated(keep=False)).sum()]))
1 loop, best of 3: 4.47 s per loop

In [122]: %timeit (df.groupby('id').store.agg(['count', 'nunique', lambda x: x.drop_duplicates(keep=False).size]))
1 loop, best of 3: 11 s per loop