我在使用pandas groupby处理分类数据时遇到了一些问题。理论上,它应该是超级高效的:你是通过整数而不是字符串来分组和索引的。但它坚持认为,当按多个类别分组时,* 类别的每一种组合 * 都必须考虑在内。
我有时候使用分类,即使常见字符串的密度很低,因为这些字符串很长,这样可以节省内存/提高性能。有时候每列有数千个分类。当按3列分组时,pandas
强制我们保存1000^3个组的结果。
我的问题:有没有一种方便的方法可以将groupby
与类别一起使用,同时避免这种不愉快的行为?我不想寻找以下任何解决方案:
- 通过
numpy
重新创建所有功能。 - 不断转换为
groupby
之前的字符串/代码,稍后恢复为类别。 - 从组列生成元组列,然后按元组列分组。
我希望有一种方法可以修改这个特殊的pandas
特性。下面是一个简单的例子。我希望在输出中有12个类别,而不是4个类别。
import pandas as pd
group_cols = ['Group1', 'Group2', 'Group3']
df = pd.DataFrame([['A', 'B', 'C', 54.34],
['A', 'B', 'D', 61.34],
['B', 'A', 'C', 514.5],
['B', 'A', 'A', 765.4],
['A', 'B', 'D', 765.4]],
columns=(group_cols+['Value']))
for col in group_cols:
df[col] = df[col].astype('category')
df.groupby(group_cols, as_index=False).sum()
Group1 Group2 Group3 Value
# A A A NaN
# A A C NaN
# A A D NaN
# A B A NaN
# A B C 54.34
# A B D 826.74
# B A A 765.40
# B A C 514.50
# B A D NaN
# B B A NaN
# B B C NaN
# B B D NaN
- 奖金更新**
Pandas开发团队没有很好地解决这个问题(cf github.com/pandas-dev/pandas/issues/17594)。因此,我希望得到解决以下问题的回复:
1.参考panda源代码,为什么在groupby操作中对分类数据的处理不同?
1.为什么当前的实现是首选?我知道这是主观的,但我很难找到这个问题的答案。当前的行为在许多情况下是禁止的,没有繁琐的,潜在的昂贵的工作区。
1.有没有一个干净的解决方案来覆盖panda在groupby操作中对分类数据的处理?注意3条不可行的路线(下降到numpy;转换为代码/从代码转换;通过元组列创建和分组)。我更喜欢一个"Pandas兼容"的解决方案,以最小化/避免其他Pandas分类功能的损失。
1.Pandas开发团队的回应,支持并澄清现有的治疗。还有,为什么考虑所有的类别组合不能配置为布尔参数?
- 奖金更新#2**
需要说明的是,我并不期待上面4个问题的答案,我想问的主要问题是,是否有可能或者建议重写pandas
库方法,以便以一种便于groupby
/set_index
操作的方式来处理类别。
6条答案
按热度按时间rbl8hiat1#
从Pandas 0.23.0开始,
groupby
method现在可以接受一个参数observed
,如果将其设置为True
(默认为False),则可以修复此问题。以下代码与问题中的代码完全相同,只是添加了observed=True
:4xrmg8kj2#
我找到了一个很好的解决方案。我会用一个更好的解释来编辑我的帖子。但同时,这个方案对你来说好吗?
所以这个问题的答案感觉更像是一个适当的编程,而不是一个普通的Pandas问题。所有分类序列都是一堆索引到分类名称中的数字。我对这些底层数字执行了groupby操作,因为它们不存在与分类列相同的问题。完成此操作后,我必须重命名列。然后我使用from_代码构造函数来创建有效地将整数列表转换回分类列。
我知道这不是你的答案,但我已经把我的解决方案变成了一个小函数,为将来遇到这个问题的人服务。
这样称呼它:
iqjalb3h3#
我发现这种行为类似于分类数据的操作部分中记录的行为。
特别是,类似于
描述
Series
和groupby
中相关行为的其他一些词。在本节的最后还有一个透视表示例。除了Series. min()、Series. max()和Series. mode()之外,分类数据还可以执行以下操作:
Series. value_counts()等Series方法将使用所有类别,即使某些类别不存在于数据中:
Groupby还将显示"未使用"的类别:
这些词和例子引用自分类数据。
2ul0zpep4#
这里有很多问题需要回答。
让我们从理解什么是“类别”开始...
分类数据类型的定义
引用Pandas文件中的“分类数据”:
分类是Pandas数据类型,对应于统计中的分类变量:一个变量,它只能取有限的,通常是固定的,可能值的数量(***类别;例如性别、社会阶层、血型、国家归属、观察时间或通过李克特量表的等级。
这里我想重点谈两点:
1.分类值作为统计变量的定义:
基本上,这意味着我们必须从统计学的Angular 来看待它们,而不是从“常规”编程的Angular 来看待它们。也就是说,它们不是“枚举”。统计分类变量有特定的操作和用例,你可以在wikipedia中阅读更多关于它们的信息。
在第二点之后,我将详细讨论这一点。
1.类别是R中的级别:
如果我们了解
R
水平和因子,我们就能更好地理解分类。我对R了解不多,但我发现this source简单而足够,下面引用一个有趣的例子:
基本上,这告诉我们,显示/使用所有类别,即使它们是不需要的,并不罕见,实际上,这是默认的行为!
这是由于分类变量在统计学中的常见使用情况,几乎在所有情况下,你***都***关心所有的分类,即使它们没有被使用,以Pandas函数cut为例。
我希望你现在已经明白了为什么Pandas会有这种行为。
分类变量上的## GroupBy
至于为什么
groupby
考虑所有类别的组合:我不能肯定,但我最好的猜测是,基于对源代码的快速审查(和你提到的github问题),他们认为分类变量的groupby
是它们之间的相互作用。因此,它应该考虑所有的对/元组(像笛卡尔乘积)。AFAIK,当你试图做像ANOVA这样的事情时,这很有帮助。这也意味着,在这种情况下,您不能用通常的类似SQL的术语来理解它。
解决方案?
好吧,但如果你不想这样呢?
据我所知,并考虑到我昨晚花了一个晚上在Pandas源代码中跟踪这个,你不能“禁用”它,它在每个关键步骤都是硬编码的。
然而,由于
groupby
的工作方式,实际的“扩展”只有在需要时才会发生,例如,在组上调用sum
或试图打印它们时。因此,您可以执行以下任一操作以仅获取所需的组:
我知道这对你来说是不可能的,但我有99%的把握,没有直接的方法来做到这一点。
我同意应该有一个布尔变量来禁用这种行为,并使用“常规的”类似SQL的变量。
wpcxdonn5#
我在调试类似的东西时发现了这个帖子。非常好的帖子,而且我真的很喜欢包含边界条件!
下面是实现初始目标的代码:
这种解决方案的缺点是,它会导致一个分层的列索引,您可能希望将其扁平化(特别是在您有多个统计数据的情况下)。
我不知道为什么示例方法:
使用分类变量的所有唯一组合,而.agg()方法:
忽略未使用的组级别组合。这似乎不一致。很高兴我们可以使用.agg()方法,而不必担心笛卡尔组合爆炸。
此外,我认为与笛卡尔积相比,唯一基数计数低得多是很常见的。想想所有数据包含“州”、“县”、“邮编”等列的情况...这些都是嵌套变量,许多数据集都有高度嵌套的变量。
在我们的例子中,分组变量的笛卡尔积和自然出现的组合之间的差异超过1000 x(起始数据集超过1,000,000行)。
因此,我会投票赞成将observed=True作为默认行为。
nwlqm0z16#
使用分类数据类型的主要优点是:
缺点是:
您可以从这篇文章中获得更深入的信息:https://medium.com/gitconnected/pandas-category-type-pros-and-cons-1bcac1bdea71