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

标签 python pandas diff

我有一个数据框,我正在尝试向它附加一列顺序差异。我找到了一种我非常喜欢的方法(并且可以很好地概括我的用例)。但一路上我注意到一件奇怪的事情。你能帮我理解一下吗?

以下是一些具有正确结构的数据(以答案 here 为模型的代码):

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

这里发生了什么?当你在 Pandas 对象上调用 .diff 方法时,不只是调用 np.diff 吗?我知道 DataFrame 类上有一个 diff 方法,但我不知道如何在没有 的情况下将其传递给 transform我用来使 data1 工作的 lambda 函数语法。我错过了什么吗?为什么 data3 中的 diffs 列有问题?如何在 transform 中调用 Pandas diff 方法,而无需编写 lambda 来执行它?

最佳答案

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

只需传递一个lambda进行transform(这相当于直接传递一个functon对象,例如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__ 输出)。我不太清楚为什么,请查看更多信息 here .所以底线是 np.diff 没有正确处理索引并进行自己的计算(在这种情况下是错误的)。

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

关于python - 使用 groupby 后在 Pandas 中计算 np.diff 会导致意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20670726/

相关文章:

python - 通过动态生成的索引在 numpy ndarray 中建立索引

python - 从 Pandas 数据框中过滤所需行的正则表达式

python - 使用 OneHotEncoder 拆分调查数据

python - 将 NaN 用于无法使用 astype 转换的值

css - 使用导入合并 CSS 文件

command-line - 命令行差异实用程序

python - 无法使用 pip 安装 pygame,因为在为 pygame 运行 vsetup.py bdist_wheel 时出现错误

Python循环速度源

python - 生成具有从不重叠的随机开始和结束日期的多个对象?

git - 使用 git word-diff 时 stash 未更改的行