按列和行值对数据进行分组

时间:2017-01-03 14:51:10

标签: python pandas

我有以下数据框df

df =

REGION   GROUP_1   GROUP_2   GROUP_3
Reg1     AAA       BBB       AAA
Reg2     BBB       AAA       CCC
Reg1     BBB       CCC       CCC

我需要计算按GROUP_1分组的GROUP_2GROUP_3REGION值的唯一出现次数(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数据需要花费太多时间。由于计算时间很长,我甚至无法检查整个数据集的结果。在我看来,代码中有问题或者可以简化。

2 个答案:

答案 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_'))

enter image description here

获得单位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())

enter image description here

稍快的方法:

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}}列。这占了时间的主要部分。然后,stackgroupbyvalue_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()

enter image description here

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