我有一个数据框,我试图在其中添加一列顺序差异.我找到了一个我喜欢的方法(并且很好地概括了我的用例).但是我注意到了一个奇怪的事情.你能帮我理解吗?
以下是一些具有正确结构的数据(代码在此处建模的代码):
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.我想这样做而不会以任何其他方式扰乱数据帧(即我不希望根据进行差分所需的内容重新排序生成的DataFrame).以下代码有效:
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
类上有一个方法,但是如果没有我用来制作工作transform
的lambda
函数语法,我无法弄清楚如何传递它data1
.我错过了什么吗?为什么diffs
柱子是data3
螺旋状的?如何调用Pandas diff
方法transform
而无需编写代码lambda
?
很容易重现的例子!更多问题应该是这样的!
只需传递一个lambda进行转换(这相当于直接传递afuncton对象,例如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个.
您可以看到Series .diff()
方法与以下内容不同np.diff()
:
In [11]: data.value.diff() # Note the NaN Out[11]: 0 NaN 1 -0.410069 2 0.523736 3 -0.114340 4 -0.014955 5 -0.090033 6 -0.125686 7 0.414622 8 -0.319616 Name: value, dtype: float64 In [12]: np.diff(data.value.values) # the values array of the column Out[12]: array([-0.41006867, 0.52373625, -0.11434009, -0.01495459, -0.09003298, -0.12568619, 0.41462233, -0.31961629]) In [13]: np.diff(data.value) # on the column (Series) Out[13]: 0 NaN 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 NaN Name: value, dtype: float64 In [14]: np.diff(data.value.index) # er... on the index Out[14]: Int64Index([8], dtype=int64) In [15]: np.diff(data.value.index.values) Out[15]: array([1, 1, 1, 1, 1, 1, 1, 1])