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

使用groupby后在Pandas中计算np.diff会导致意外结果

上官培
2023-03-14
问题内容

我有一个数据框,并且我试图向其添加一列顺序差异。我发现了一种我非常喜欢的方法(并且对于我的用例而言,它具有很好的概括性)。但是我一路上注意到一件奇怪的事。你能帮我弄清楚吗?

以下是一些具有正确结构的数据:

import pandas as pd
import numpy as np
import random
from itertools import product

random.seed(1)       # so you can play along at home
np.random.seed(2)    # ditto

# make a list of dates for a few periods
dates = pd.date_range(start='2013-10-01', periods=4).to_native_types()
# make a list of tickers
tickers = ['ticker_%d' % i for i in range(3)]
# make a list of all the possible (date, ticker) tuples
pairs = list(product(dates, tickers))
# put them in a random order
random.shuffle(pairs)
# exclude a few possible pairs
pairs = pairs[:-3]
# make some data for all of our selected (date, ticker) tuples
values = np.random.rand(len(pairs))

mydates, mytickers = zip(*pairs)
data = pd.DataFrame({'date': mydates, 'ticker': mytickers, 'value':values})

好,很好。这给了我这样的框架:

     date        ticker      value
0    2013-10-03  ticker_2    0.435995
1    2013-10-04  ticker_2    0.025926
2    2013-10-02  ticker_1    0.549662
3    2013-10-01  ticker_0    0.435322
4    2013-10-02  ticker_2    0.420368
5    2013-10-03  ticker_0    0.330335
6    2013-10-04  ticker_1    0.204649
7    2013-10-02  ticker_0    0.619271
8    2013-10-01  ticker_2    0.299655

我的目标是向此数据框添加一个新列,其中将包含顺序更改。数据需要这样做,但是排序和差异需要“逐行代码”完成,以便另一个代码中的间隔不会导致给定代码的NA。我想做到这一点而不会以任何其他方式干扰数据框(即,我不希望根据进行区分的必要性对结果数据框进行重新排序)。以下代码有效:

data1 = data.copy() #let's leave the original data alone for later experiments
data1.sort(['ticker', 'date'], inplace=True)
data1['diffs'] = data1.groupby(['ticker'])['value'].transform(lambda x: x.diff())
data1.sort_index(inplace=True)
data1

返回

     date        ticker      value       diffs
0    2013-10-03  ticker_2    0.435995    0.015627
1    2013-10-04  ticker_2    0.025926   -0.410069
2    2013-10-02  ticker_1    0.549662    NaN
3    2013-10-01  ticker_0    0.435322    NaN
4    2013-10-02  ticker_2    0.420368    0.120713
5    2013-10-03  ticker_0    0.330335   -0.288936
6    2013-10-04  ticker_1    0.204649   -0.345014
7    2013-10-02  ticker_0    0.619271    0.183949
8    2013-10-01  ticker_2    0.299655    NaN

到现在为止还挺好。如果我将上面的中间行替换为此处显示的更简洁的代码,则一切仍然有效:

data2 = data.copy()
data2.sort(['ticker', 'date'], inplace=True)
data2['diffs'] = data2.groupby('ticker')['value'].diff()
data2.sort_index(inplace=True)
data2

快速检查表明,实际上data1等于data2。但是,如果我这样做:

data3 = data.copy()
data3.sort(['ticker', 'date'], inplace=True)
data3['diffs'] = data3.groupby('ticker')['value'].transform(np.diff)
data3.sort_index(inplace=True)
data3

我得到一个奇怪的结果:

     date        ticker     value       diffs
0    2013-10-03  ticker_2    0.435995    0
1    2013-10-04  ticker_2    0.025926   NaN
2    2013-10-02  ticker_1    0.549662   NaN
3    2013-10-01  ticker_0    0.435322   NaN
4    2013-10-02  ticker_2    0.420368   NaN
5    2013-10-03  ticker_0    0.330335    0
6    2013-10-04  ticker_1    0.204649   NaN
7    2013-10-02  ticker_0    0.619271   NaN
8    2013-10-01  ticker_2    0.299655    0

这里发生了什么?当您.diff在Pandas对象上调用方法时,它不仅在调用np.diff吗?我知道类上有一个diff方法DataFrame,但是如果没有我以前用来工作transformlambda函数语法,我无法弄清楚如何将其传递给它data1。我想念什么吗?为什么diffs色谱柱是data3螺旋形的?我如何difftransform不编写A的情况下调用Pandas方法lambda


问题答案:

好容易重现的例子!更多问题应该是这样!

只需传递一个lambda进行转换(这等同于直接传递函数对象,例如直接传递np.diff(或Series.diff)。因此,这等效于data1 / data2

In [32]: data3['diffs'] = data3.groupby('ticker')['value'].transform(Series.diff)

In [34]: data3.sort_index(inplace=True)

In [25]: data3
Out[25]: 
         date    ticker     value     diffs
0  2013-10-03  ticker_2  0.435995  0.015627
1  2013-10-04  ticker_2  0.025926 -0.410069
2  2013-10-02  ticker_1  0.549662       NaN
3  2013-10-01  ticker_0  0.435322       NaN
4  2013-10-02  ticker_2  0.420368  0.120713
5  2013-10-03  ticker_0  0.330335 -0.288936
6  2013-10-04  ticker_1  0.204649 -0.345014
7  2013-10-02  ticker_0  0.619271  0.183949
8  2013-10-01  ticker_2  0.299655       NaN

[9 rows x 4 columns]

我相信这np.diff不会遵循numpy自己的unfunc准则来处理数组输入(从而尝试各种方法来强制输入并发送输出,例如__array____array_wrap__基于输出的输入)。我不太确定为什么,请在此处查看更多信息。因此,最重要的np.diff是无法正确处理索引并自行计算(在这种情况下是错误的)。

Pandas有很多方法,它们不仅仅调用numpy函数,主要是因为它们处理不同的dtypes,处理nans,并且在这种情况下,处理“特殊”差异。例如,您可以将时间频率传递给datelike-
index,在此它可以计算实际求差n的数量。



 类似资料:
  • 问题内容: 我有以下形式的数据: 组内的非空值始终相同。我想对每个组(如果存在)的非空值进行一次计数,然后找到每个值的总数。 我目前正在以以下方式(笨拙和低效)进行此操作: 我敢肯定,有一种方法可以更干净地执行此操作,而无需使用循环,但是我似乎无法解决问题。任何帮助将非常感激。 问题答案: 我认为您可以使用: 的另一种解决方案,然后创建new by ,将其重塑为by和last :

  • 问题内容: df = pd.DataFrame({‘A’ : [‘foo’, ‘bar’, ‘foo’, ‘bar’, ‘foo’, ‘bar’, ‘foo’, ‘foo’], ‘B’ : [‘one’, ‘one’, ‘two’, ‘three’, ‘two’, ‘two’, ‘one’, ‘three’], ‘C’ : [np.nan, ‘bla2’, np.nan, ‘bla3’, np.n

  • 问题内容: 我在玩耍以获得更好的itertools感觉,所以我按数字对元组列表进行了分组,并试图得到结果组的列表。但是,当我将结果转换为列表时,会得到一个奇怪的结果:除了最后一组以外的所有内容都是空的。这是为什么?我以为将迭代器转换为列表效率不高,但永远不会改变行为。我猜列表是空的,因为遍历了内部迭代器,但是何时/何地发生? 问题答案: 从 文档中 : 返回的组本身就是一个与共享底层可迭代对象的迭

  • 问题内容: 每当我编写包含ArrayUtil的代码时,都会导致意外错误: 我使用Eclipse编写代码,“ ArrayUtil”下始终有一个红色下划线。我究竟做错了什么? 问题答案: 您的ArrayUtil属于哪个软件包?没有这些信息,没人能确定地回答。 你到这里了吗?如果是,则您的签名看起来正确。您可能尚未导入它,或者该类不在您的CLASSPATH中。Eclipse告诉您更正其中一项。

  • 问题内容: 我正在尝试编写一种获取a的方法,以验证数字是否在点后有东西,如果有,则返回a ,如果没有则返回a 。 输出: 因此,我想要的一切都发生在method中,但没有发生在method中。这些方法似乎必须完成相同的工作。但是我做错了什么? 问题答案: 正如其他答案所指出的,此行为是因为三元表达式的两个可能结果都必须具有相同的类型。 因此,您要做的所有事情都可以使三元版本的工作方式与将强制转换为

  • 问题内容: 例如,我有下表: 分组后: 我需要的是删除每个组中的行,其中列中的数量小于组中column的所有行中的最大值。好吧,我在将这个问题翻译和表达为英语时遇到了问题,因此这里是示例: 组中列中的行的最大值: 8 所以我想删除带有索引的行,并保留带有索引的行, 组中列中的行的最大值: 5 所以我想删除带有索引的行并保留带有索引的行 我尝试使用熊猫过滤器功能,但是问题是它一次在组中的所有行上运行