我有一个数据框,我正在尝试向它附加一列顺序差异。我找到了一种我非常喜欢的方法(并且可以很好地概括我的用例)。但一路上我注意到一件奇怪的事情。你能帮我理解一下吗?
以下是一些具有正确结构的数据(以答案 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
工作的 lambdadata3
中的 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/