Python 按列和行值对数据分组

Python 按列和行值对数据分组,python,pandas,Python,Pandas,我有以下数据帧df: df = REGION GROUP_1 GROUP_2 GROUP_3 Reg1 AAA BBB AAA Reg2 BBB AAA CCC Reg1 BBB CCC CCC 我需要计算每个区域分组的GROUP\u 1、GROUP\u 2和GROUP\u 3值的唯一出现次数(在我的真实数据集中GROUP\u列的数量为50) 对于上述示例,结果应如下所示: resul

我有以下数据帧
df

df =

REGION   GROUP_1   GROUP_2   GROUP_3
Reg1     AAA       BBB       AAA
Reg2     BBB       AAA       CCC
Reg1     BBB       CCC       CCC
我需要计算每个
区域
分组的
GROUP\u 1
GROUP\u 2
GROUP\u 3
值的唯一出现次数(在我的真实数据集中
GROUP\u
列的数量为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的数据占用的时间太长。我甚至不能检查整个数据集的结果,因为计算时间很长。在我看来,代码中有错误或者可以简化

  • 设置索引
  • 值\u计数
  • notnull
    将1s和2s转换为
    True
    并将
    np.nan
    转换为False
  • groupby
    +
    sum


更快

更快

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

您可以从删除
组X
列中存在的重复值开始。然后在
lreshape
的帮助下,将它们合并为一个

通过将REGION作为分组键执行
groupby
,并计算
value\u计数
,以获得组列中存在的各个唯一计数

最后,
unstack
将多索引系列添加到数据帧中,并为获得的列标题添加可选前缀

慢进近:

要获得平坦的
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())


稍微快一点的方法:

多索引的帮助下,我们也可以从_数组中计算唯一的行

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
更快,因为它在找到唯一元素后不执行排序操作),同时遍历与
组X
列对应的数组。这占用了大部分时间。然后,
stack
groupby
value\u计数
,最后
取消堆叠

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

我真的不明白得到结果的逻辑…为什么Reg1 COUNT\u BBB的结果是2,而COUNT\u AAA和COUNT\u CCC的结果是1?在这种情况下,计数不应该等于2吗?Reg2的结果很清楚,因为您只有一行,并且有三个“类型”每行仅出现一次。对于Reg1,计数_BBB为2,因为BBB在组_2中出现1次,在组_1中出现1次,在第一行和第三行中出现1次(因此,总共2次唯一(每行)发生率。在Reg1计数中,AAA等于1,因为它在第一行中出现两次,但我只计算一次,因为我对每行的唯一发生率感兴趣。完美。我只希望在这一行中附带一点解释。初学者更容易将其分解。为什么Reg1的AAA和CCC等于2?很简单应该是1。AAA在第一行中出现两次,因此我只想计算一次,因为我对组值的唯一(每行)出现感兴趣。确实,此解决方案非常快。是否有可能以某种方式加速此代码?它给出了正确的结果,但在1 Gb上运行的时间太长(确实没有太多数据)。我知道这不是很有效。我会努力优化它。@NickilMaveli我已经更新了我的帖子。看看你是否喜欢。你的最后两种方法太好了。我总是害怕使用循环,尤其是在数据量大的时候。但这被证明是难以置信的快。看到这一点,我还添加了一个循环解决方案和一个非循环解决方案因此,使用多索引的快速变体可以做同样的事情。
(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())
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')
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()