我有以下数据框df
:
df =
REGION GROUP_1 GROUP_2 GROUP_3
Reg1 AAA BBB AAA
Reg2 BBB AAA CCC
Reg1 BBB CCC CCC
我需要计算按GROUP_1
分组的GROUP_2
,GROUP_3
和REGION
值的唯一出现次数(GROUP_
列的数量在我的真实数据集中是50。)
对于上面的示例,结果应如下所示:
result =
REGION COUNT_AAA COUNT_BBB COUNT_CCC
Reg1 1 2 1
Reg2 1 1 1
这是我的代码:
df = (pd.melt(df, id_vars=['REGION'], value_name='GROUP')
.drop('variable', axis=1).drop_duplicates()
.groupby(['REGION', 'GROUP']).agg({'GROUP' : 'count'})
.reset_index())
问题是1Gb数据需要花费太多时间。由于计算时间很长,我甚至无法检查整个数据集的结果。在我看来,代码中有问题或者可以简化。
答案 0 :(得分:4)
您可以从删除GROUP_X
列中存在的重复值开始。然后在lreshape
的帮助下,将这些内容合并到一个GROUP
列中。
通过将 REGION 作为分组键来执行groupby
,并计算value_counts
以获取 GROUP 列中相应的唯一计数。
最后,unstack
使多索引系列成为数据帧,并为获得的列标题添加可选前缀。
缓慢的方法:
(pd.lreshape(df.apply(lambda x: x.drop_duplicates(), 1),
{"GROUP": df.filter(like='GROUP').columns})
.groupby('REGION')['GROUP'].value_counts().unstack().add_prefix('COUNT_'))
获得单位DF
:
(pd.lreshape(df.apply(lambda x: x.drop_duplicates(), 1),
{"GROUP": df.filter(like='GROUP').columns}).groupby('REGION')['GROUP'].value_counts()
.unstack().add_prefix('COUNT_').rename_axis(None, 1).reset_index())
稍快的方法:
在MultiIndex.from_arrays
的帮助下,我们也可以计算唯一的行。
midx = pd.MultiIndex.from_arrays(df.filter(like='GROUP').values, names=df.REGION.values)
d = pd.DataFrame(midx.levels, midx.names)
d.stack().groupby(level=0).value_counts().unstack().rename_axis('REGION')
更快的方法:
更快的方法是使用pd.unique
创建唯一行值(比np.unique
更快,因为它在找到唯一元素后不执行排序操作),同时迭代对应于{{的GROUP_X
1}}列。这占了时间的主要部分。然后,stack
,groupby
,value_counts
,最后再unstack
。
d = pd.DataFrame([pd.unique(i) for i in df.filter(like='GROUP').values], df.REGION)
d.stack().groupby(level=0).value_counts(sort=False).unstack()
答案 1 :(得分:3)
set_index
value_counts
notnull
将1和2转换为True
,将np.nan
转换为False groupby
+ sum
df.set_index('REGION').apply(
pd.value_counts, 1).notnull().groupby(level=0).sum().astype(int)
AAA BBB CCC
REGION
Reg1 1 2 1
Reg2 1 1 1
更快
val = df.filter(like='GROUP').values
reg = df.REGION.values.repeat(val.shape[1])
idx = df.index.values.repeat(val.shape[1])
grp = val.ravel()
pd.Series({(i, r, g): 1 for i, r, g in zip(idx, reg, grp)}).groupby(level=[1, 2]).sum().unstack()
更快
from collections import Counter
val = df.filter(like='GROUP').values
reg = df.REGION.values.repeat(val.shape[1])
idx = df.index.values.repeat(val.shape[1])
grp = val.ravel()
pd.Series(Counter([(r, g) for _, r, g in pd.unique([(i, r, g) for i, r, g in zip(idx, reg, grp)]).tolist()])).unstack()