使用groupby后计算Pandas中的差异会导致意外结果

 Daro_olingke_572 发布于 2023-02-09 12:46

我有一个数据框,我试图在其中添加一列顺序差异.我找到了一个我喜欢的方法(并且很好地概括了我的用例).但是我注意到了一个奇怪的事情.你能帮我理解吗?

以下是一些具有正确结构的数据(代码在此处建模的代码):

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类上有一个方法,但是如果没有我用来制作工作transformlambda函数语法,我无法弄清楚如何传递它data1.我错过了什么吗?为什么diffs柱子是data3螺旋状的?如何调用Pandas diff方法transform而无需编写代码lambda

2 个回答
  • 很容易重现的例子!更多问题应该是这样的!

    只需传递一个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个.

    2023-02-09 12:48 回答
  • 您可以看到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])
    

    2023-02-09 12:48 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有