Python-在组对象上应用vs变换

考虑以下数据框:

     A      B         C         D

0 foo one 0.162003 0.087469

1 bar one -1.156319 -1.526272

2 foo two 0.833892 -1.666304

3 bar three -2.026673 -0.322057

4 foo two 0.411452 -0.954371

5 bar two 0.765878 -0.095968

6 foo one -0.654890 0.678091

7 foo three -1.789842 -1.130922

以下命令起作用:

> df.groupby('A').apply(lambda x: (x['C'] - x['D']))

> df.groupby('A').apply(lambda x: (x['C'] - x['D']).mean())

但以下任何一项均无效:

> df.groupby('A').transform(lambda x: (x['C'] - x['D']))

ValueError: could not broadcast input array from shape (5) into shape (5,3)

> df.groupby('A').transform(lambda x: (x['C'] - x['D']).mean())

TypeError: cannot concatenate a non-NDFrame object

为什么? 文档中的示例似乎建议通过调用transform组,可以进行行操作处理:

# Note that the following suggests row-wise operation (x.mean is the column mean)

zscore = lambda x: (x - x.mean()) / x.std()

transformed = ts.groupby(key).transform(zscore)

换句话说,我认为转换本质上是一种特定的应用类型(不聚合的类型)。我哪里错了?

供参考,以下是上面原始数据帧的构造:

df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',

'foo', 'bar', 'foo', 'foo'],

'B' : ['one', 'one', 'two', 'three',

'two', 'two', 'one', 'three'],

'C' : randn(8), 'D' : randn(8)})

回答:

transformapplygroupby方法之间有两个主要区别。

  • 输入:
  • apply将每个组的所有列作为DataFrame隐式传递给自定义函数。
  • 同时transform将每个组的每一列作为系列分别传递给自定义函数。
  • 输出:
  • 传递给的自定义函数apply可以返回标量,或者返回SeriesDataFrame(或numpy数组,甚至是list)。
  • 传递给的自定义函数transform必须返回与group长度相同的序列(一维Series,数组或列表)。

    因此,transform一次只能处理一个Series,而一次apply可以处理整个DataFrame

检查传递给applyor的自定义函数的输入可能会很有帮助transform。

例子

让我们创建一些示例数据并检查组,以便你可以了解我在说什么:

import pandas as pd

df = pd.DataFrame({'State':['Texas', 'Texas', 'Florida', 'Florida'],

'a':[4,5,1,3], 'b':[6,10,3,11]})

df

让我们创建一个简单的自定义函数,该函数打印出隐式传递的对象的类型,然后引发错误,以便可以停止执行。

def inspect(x):

print(type(x))

raise

现在让我们将此函数传递给groupby apply和transformmethod,以查看传递给它的对象:

df.groupby('State').apply(inspect)

<class 'pandas.core.frame.DataFrame'>

<class 'pandas.core.frame.DataFrame'>

RuntimeError

如你所见,DataFrame被传递到inspect函数中。你可能想知道为什么将DataFrame类型打印两次。熊猫两次参加第一组比赛。这样做是为了确定是否存在快速完成计算的方法。这是你不应该担心的次要细节。

现在,让我们用 transform

df.groupby('State').transform(inspect)

<class 'pandas.core.series.Series'>

<class 'pandas.core.series.Series'>

RuntimeError

它传递了一个Series-一个完全不同的Pandas对象。

因此,一次transform只能使用一个系列。它不可能同时作用于两根色谱柱。因此,如果尝试a从b自定义函数中减去column ,则会出现错误transform。见下文:

def subtract_two(x):

return x['a'] - x['b']

df.groupby('State').transform(subtract_two)

KeyError: ('a', 'occurred at index a')

当熊猫试图找到a不存在的Series索引时,我们得到一个KeyError 。你可以通过完整applyDataFrame 来完成此操作:

df.groupby('State').apply(subtract_two)

State

Florida 2 -2

3 -8

Texas 0 -2

1 -5

dtype: int64

输出是一个Series,并且保留了原始索引,因此有些混乱,但是我们可以访问所有列。

显示传递的熊猫对象

它可以在自定义函数中显示整个pandas对象,从而提供更多帮助,因此你可以确切地看到正在使用的对象。你可以使用print我喜欢使用模块中的display函数的语句,IPython.display以便在Jupyter笔记本中以HTML形式很好地输出DataFrame:

from IPython.display import display

def subtract_two(x):

display(x)

return x['a'] - x['b']

变换必须返回与组大小相同的一维序列

另一个区别是transform必须返回与该组相同大小的一维序列。在此特定情况下,每个组都有两行,因此transform必须返回两行的序列。如果没有,则会引发错误:

def return_three(x):

return np.array([1, 2, 3])

df.groupby('State').transform(return_three)

ValueError: transform must return a scalar value for each group

该错误消息并不能真正描述问题。你必须返回与组相同长度的序列。因此,这样的功能将起作用:

def rand_group_len(x):

return np.random.rand(len(x))

df.groupby('State').transform(rand_group_len)

a b

0 0.962070 0.151440

1 0.440956 0.782176

2 0.642218 0.483257

3 0.056047 0.238208

如果仅从自定义函数返回单个标量,transform则将其用于组中的每一行:

def group_sum(x):

return x.sum()

df.groupby('State').transform(group_sum)

a b

0 9 16

1 9 16

2 4 14

3 4 14

以上是 Python-在组对象上应用vs变换 的全部内容, 来源链接: utcz.com/qa/419722.html

回到顶部