当前位置: 首页 > 面试题库 >

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

辛盛
2023-03-14
问题内容

考虑以下数据框:

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

问题答案:

apply和之间的两个主要区别transform

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

如果仅从自定义函数返回单个标量,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


 类似资料:
  • 问题内容: 我正在尝试验证实例属性和类属性之间的区别,该区别由2012年11月1日发布的Python教程2.7.3版第9章:类,第66页最后一行( 源 ): 实例对象的有效方法名称取决于其类。根据定义,作为函数对象的类的所有属性都定义了其实例的相应方法。因此,在我们的示例中,xf是有效的方法引用,因为MyClass.f是函数,而xi则不是,因为MyClass.i不是。 但是xf与MyClass.f

  • 问题内容: 有没有一种干净的方法可以在没有lambda或列表理解的情况下在Python对象上应用函数列表?就像Haskell表达式一样: 在Python中使用lambda的示例: 它可以扩展到类函数吗? 也许来自运算符或itertools的东西? 问题答案: 我认为这应该符合您的“职能”标准,要回答您的问题,我认为没有一种干净的方法,您应该适应列出理解。 如@JFSebastian所建议 这是一种

  • 问题内容: 在一个我目前正在从事的项目中,我遇到了一个角度异常: 在寻找解决方案的搜索中,我直接在浏览器中输入了Web服务的URL,但令人惊讶的是,我没有收到预期的数组。 Web服务类: 当我输入网址时,我希望看到带有JSON对象的JSON数组: 但是,相反,我收到的JSON对象的属性与我期望的JSON对象相同,没有任何数组: 所以我想知道为什么没有数组,当我添加另一个Clazz对象时会发生什么。

  • 我用的是angular 5。我尝试在下面的html数组中使用嵌套循环 对象: HTML: 我得到以下解析错误: 我在app.module.ts导入了BrowserModul和Common Modul,这样用户就可以将一周中的任何一天的时间表复制到一周的其余时间。 编辑:我的代码中的实际超文本标记语言:

  • 如您所知,< code>java.util.Objects是 这个类由用于操作对象的静态实用程序方法组成。 其中一个方法是< code>Objects.isNull()。 我的理解是< code>Objects.isNull()会通过省略第二个< code>=来消除意外地将空值赋给object的可能性。 但是,API注释指出: 此方法存在,可用作谓词、筛选器(对象::isNull) 是否有任何原因

  • 问题内容: 代码段-1 代码段-2 我在第一个代码段中遇到了竞争。我知道这是因为我正在获得对不可变对象(类型为Integer)的锁定。 我已经写了第二个代码片段,这再次使“布尔”不变。但这有效(输出运行中不显示竞争条件)。如果我正确理解了上一个问题的解决方案,则以下是出现问题的一种可能方法 线程1锁定由指向的对象(例如A) 线程2现在试图获取由指向的对象的锁,并进入A的等待队列。 线程1进入同步块