通过在具有 pandas 的列上分组来汇总数据框

Summarize dataframe by grouping on a column with pandas

我有一个数据框

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()

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

您可以使用 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 版本,传递字典可以简化您的代码(在 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,以这种方式,:

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 

groupby with agg with count and nunique. Last function is a bit complicated - need count all non dupes using inverting duplicatedsum一起使用:

如果需要计数 NaNs 使用 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