在groupby中传递给transform或apply的Pandas数据类型是什么?

6
尝试调试groupby函数应用时,有人建议我使用虚拟函数来“查看每个组传递了什么”进入该函数。当然,我愿意尝试:
import numpy as np
import pandas as pd

np.random.seed(0) # so we can all play along at home

categories = list('abc')
categories = categories * 4
data_1 = np.random.randn(len(categories))
data_2 = np.random.randn(len(categories))

df = pd.DataFrame({'category': categories, 'data_1': data_1, 'data_2': data_2})

def f(x):
    print type(x)
    return x

print 'single column transform'
df.groupby(['category'])['data_1'].transform(f)
print '\n'

print 'single column (nested) transform'
df.groupby(['category'])[['data_1']].transform(f)
print '\n'

print 'multiple column transform'
df.groupby(['category'])[['data_1', 'data_2']].transform(f)

print '\n'
print '\n'

print 'single column apply'
df.groupby(['category'])['data_1'].apply(f)
print '\n'

print 'single column (nested) apply'
df.groupby(['category'])[['data_1']].apply(f)
print '\n'

print 'multiple column apply'
df.groupby(['category'])[['data_1', 'data_2']].apply(f)

这将以下内容放入我的标准输出:
single column transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>


single column (nested) transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>


multiple column transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>




single column apply
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>


single column (nested) apply
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>


multiple column apply
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>

看起来是这样的:

  • 转换
    • 单列:3个Series
    • 单列(嵌套):2个Series和3个DataFrame
    • 多列:3个Series和3个DataFrame
  • 应用
    • 单列:3个Series
    • 单列(嵌套):4个DataFrame
    • 多列:4个DataFrame

这里发生了什么?有人能解释一下为什么每个调用都会导致传递给指定函数的对象系列如上所述吗?


1
请仅返回翻译的文本内容:不需要扩展您的问题(完全回答会成为文档的良好补充);需要情况是在groupy中有两个groupers的情况(我不知道输入是否不同,但它们包括被分组对象的索引)。 - Jeff
我发现在过去的一个月里,我在学习Pandas时遇到了很多这种类型的问题。有没有好的资源可以解决这种问题?例如,一般性的“这就是Pandas在幕后是如何工作的”教程,旨在培养直觉而非深入源代码的研究和重写? - 8one6
在底层通常需要您构建一个示例,然后逐步执行代码。有些很简单,但像groupby / indexing这样的操作不是那么容易,因为它涉及到许多情况和数据类型。资源包括文档/食谱、Wes的书和SO问题。 - Jeff
1个回答

4

GroupBy.transform函数会尝试使用快速和慢速两种方法来执行您的函数。

  • 快速方法:使用DataFrame对象调用您的函数
  • 慢速方法:使用DataFrame.apply函数来调用您的函数

当快速方法的结果与慢速方法相同时,它会选择快速方法。

下面的输出表示最终选择了快速方法:

multiple column transform
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>

这是代码链接:

https://github.com/pydata/pandas/blob/master/pandas/core/groupby.py#L2277

编辑:
用于检查调用堆栈:
import numpy as np
import pandas as pd

np.random.seed(0) # so we can all play along at home

categories = list('abc')
categories = categories * 4
data_1 = np.random.randn(len(categories))
data_2 = np.random.randn(len(categories))

df = pd.DataFrame({'category': categories, 'data_1': data_1, 'data_2': data_2})

import traceback
import inspect
import itertools

def f(x):
    flag = True
    stack = itertools.dropwhile(lambda x:"#stop here" not in x, 
                                traceback.format_stack(inspect.currentframe().f_back))
    print "*"*20
    print x
    print type(x)
    print
    print "\n".join(stack)
    return x

df.groupby(['category'])[['data_1', 'data_2']].transform(f) #stop here

我有点困惑,不明白为什么每个示例中会有超过3行的“类型”。对于我的数据集,恰好有3个组。我期望每个示例包含恰好3个某物...即Pandas最终选择并要求函数处理的内容。但这似乎与上面的输出不兼容。最后两个案例都在操作4个DataFrame,没有其他东西?你能解释一下那里发生了什么吗? - 8one6
@DJ_8one6,你可以输出调用栈并分析发生了什么。 - HYRY
有没有办法强制 transform 传递多列数据框(即不是来自列的单个系列)到函数中?我基本上想要与 apply(my_func, axis=1) 相同的行为,但是强制它返回具有相同索引的结果(即 transform 应该做的事情,但是我想一次访问多个列而不是逐列工作)。 - Amelio Vazquez-Reina

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接