为什么groupby操作的行为有所不同

加布里埃尔·齐格勒

当使用pandas groupby函数并在groupby之后处理输出时,我注意到某些函数在返回的索引以及如何操作方面表现出不同。

假设我们有一个包含以下信息的数据框:

    Name   Type  ID
0  Book1  ebook   1
1  Book2  paper   2
2  Book3  paper   3
3  Book1  ebook   1
4  Book2  paper   2

如果我们这样做

df.groupby(["Name", "Type"]).sum()  

我们得到一个DataFrame

             ID
Name  Type     
Book1 ebook   2
Book2 paper   4
Book3 paper   3

其中包含一个MultiIndex以及groupby中使用的列:

MultiIndex([('Book1', 'ebook'),
            ('Book2', 'paper'),
            ('Book3', 'paper')],
           names=['Name', 'Type'])

一栏叫ID

但是如果我应用一个size()函数,结果是Series

Name   Type 
Book1  ebook    2
Book2  paper    2
Book3  paper    1
dtype: int64

最后,如果我执行pct_change(),我们只会得到结果DataFrame列:

    ID
0   NaN
1   NaN
2   NaN
3   0.0
4   0.0

TL; DR。我想知道为什么有些函数返回一个Series而另一些返回a DataFrame这使我在处理同一DataFrame中的不同操作时感到困惑。

洛兹

输出是不同的,因为聚合是不同的,并且聚合主要控制返回的内容。想想等效的数组。数据相同,但是一个“聚合”返回一个标量值,另一个返回与输入大小相同的数组

import numpy as np
np.array([1,2,3]).sum()
#6

np.array([1,2,3]).cumsum()
#array([1, 3, 6], dtype=int32)

对于DataFrameGroupBy对象的聚合也是如此。groupby所做的所有第一部分都是创建从DataFrame到组的映射。由于这实际上没有任何作用,因此没有理由为什么具有不同操作的相同groupby需要返回相同类型的输出(请参见上文)。

gp = df.groupby(["Name", "Type"])
# Haven't done any aggregations yet...

这里的另一个重要部分是我们有一个DataFrame GroupBy对象。也有Series GroupBy对象,这种差异可以改变收益。

gp
#<pandas.core.groupby.generic.DataFrameGroupBy object>

那么聚合时会发生什么?

随着DataFrameGroupBy当你选择一个集合(如sum)坍塌每组一个价值的回归将是一个数据帧,其中指数是唯一的分组键。返回值是DataFrame因为我们提供了一个DataFrameGroupBy对象。DataFrames可以有多个列,并且如果还有另一个数字列,它也将聚合在一起,因此需要DataFrame输出。

gp.sum()
#             ID
#Name  Type     
#Book1 ebook   2
#Book2 paper   4
#Book3 paper   3

另一方面,如果您使用SeriesGroupBy对象(使用选择单个列[]),那么您将获得一个Series,再次使用唯一组键的索引。

df.groupby(["Name", "Type"])['ID'].sum()
|------- SeriesGroupBy ----------|

#Name   Type 
#Book1  ebook    2
#Book2  paper    4
#Book3  paper    3
#Name: ID, dtype: int64

对于聚合返回数组(如cumsumpct_change)一个DataFrameGroupBy会返回一个数据帧和SeriesGroupBy将返回一个系列。但是索引不再是唯一的组密钥。这是因为那将毫无意义。通常,您需要在组内进行计算,然后将结果分配回原始DataFrame。结果,返回的索引就像为聚合提供的原始DataFrame一样被索引。这使得创建这些列非常简单,因为熊猫可以处理所有对齐方式

df['ID_pct_change'] = gp.pct_change()

#    Name   Type  ID  ID_pct_change
#0  Book1  ebook   1            NaN  
#1  Book2  paper   2            NaN   
#2  Book3  paper   3            NaN   
#3  Book1  ebook   1            0.0  # Calculated from row 0 and aligned.
#4  Book2  paper   2            0.0

但是呢size那个有点奇怪size一组是一个标量。该组具有多少列或这些列中的值是否缺失都无关紧要,因此向其发送DataFrameGroupBy或SeriesGroupBy对象无关紧要。结果pandas将始终返回Series同样,作为返回标量的组级别聚合,有意义的是使返回值由唯一的组键索引。

gp.size()
#Name   Type 
#Book1  ebook    2
#Book2  paper    2
#Book3  paper    1
#dtype: int64

最后,为了完整sum起见,尽管像返回这样的单个标量值的聚合,将这些值返回到原始DataFrame中该组的每一行通常很有用。但是,法线的返回.sum具有不同的索引,因此它不会对齐。您可以merge将值放回到唯一键上,但是pandas可以进行transform这些聚合。由于此处的目的是将其带回到原始DataFrame,因此对Series / DataFrame的索引与原始输入一样

gp.transform('sum')
#   ID
#0   2    # Row 0 is Book1 ebook which has a group sum of 2
#1   4
#2   3
#3   2    # Row 3 is also Book1 ebook which has a group sum of 2
#4   4

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么hide()的行为有所不同?

为什么numpy导入的行为有所不同?

为什么to_sym的行为有所不同?

<|>在Parsec中-为什么这些示例的行为有所不同?

当类中的counter较大时,为什么java线程的行为会有所不同?

为什么在此示例中,“ grep”的行为有所不同?

为什么“花括号”在JavaScript中的行为有所不同?

为什么中断和isInterrupted的行为方式有所不同?

为什么这些小型D程序的行为有所不同?

为什么ContextMenuOpening的Source对于Canvas和UserControl的行为有所不同?

为什么`Paths.get`方法的行为有所不同?

当类在函数内时,为什么类中的全局行为会有所不同?

为什么这些生成器表达式的行为有所不同?

为什么bash的脚本与stdin的行为有所不同?

为什么hasattr在使用@property方法的类和实例上的行为有所不同?

为什么此数组初始化的行为有所不同?

将CSS应用于DOM后,为什么它的行为有所不同?

为什么NumberFormatInfo在Azure环境中的行为有所不同?

为什么pidof和pgrep的行为有所不同?

为什么在C#和Java中,对流的“关闭”调用的行为有所不同?

为什么从函数调用Bash的“源”命令的行为会有所不同?

为什么在这些示例中skipWhile的行为有所不同?

为什么当类型实现接口时,行为会有所不同?

解释* Rc :: make_mut的行为以及为什么它与Mutex有所不同

为什么reference_wrapper对于内置类型的行为有所不同?

为什么嵌套类在Java和C#之间的行为有所不同?

为什么以foreach调用时,ForEach-Object的行为会有所不同?

为什么对于相同但按比例缩放的数据,绘图的行为会有所不同?

为什么`-lt`对于字符和字符串的行为有所不同?