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