我有一个数据框
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_store
和unique 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()
但我如何从中获取其他人并形成数据框
答案 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)
groupby
与agg
和count
一起使用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