Python timeseries重新采样产生意外结果

Python timeseries重新采样产生意外结果,python,pandas,Python,Pandas,这里的数据是一个有流动余额的银行账户。我想对数据进行重采样,以仅使用日终余额,因此为一天给定的最后一个值。一天可以有多个数据点,表示多个事务 In [1]: from StringIO import StringIO In [2]: import pandas as pd In [3]: import numpy as np In [4]: print "Pandas version", pd.__version__ Pandas version 0.12.0 In [5]: print

这里的数据是一个有流动余额的银行账户。我想对数据进行重采样,以仅使用日终余额,因此为一天给定的最后一个值。一天可以有多个数据点,表示多个事务

In [1]: from StringIO import StringIO

In [2]: import pandas as pd

In [3]: import numpy as np

In [4]: print "Pandas version", pd.__version__
Pandas version 0.12.0

In [5]: print "Numpy version", np.__version__
Numpy version 1.7.1

In [6]: data_string = StringIO(""""Date","Balance"
   ...: "08/09/2013","1000"
   ...: "08/09/2013","950"
   ...: "08/09/2013","930"
   ...: "08/06/2013","910"
   ...: "08/02/2013","900"
   ...: "08/01/2013","88"
   ...: "08/01/2013","87"
   ...: """)

In [7]: ts = pd.read_csv(data_string, parse_dates=[0], index_col=0)

In [8]: print ts
            Balance
Date               
2013-08-09     1000
2013-08-09      950
2013-08-09      930
2013-08-06      910
2013-08-02      900
2013-08-01       88
2013-08-01       87
我预计“2013-08-09”是1000,但绝对不是中间的950

In [10]: ts.Balance.resample('D', how='last')
Out[10]: 
Date
2013-08-01     88
2013-08-02    900
2013-08-03    NaN
2013-08-04    NaN
2013-08-05    NaN
2013-08-06    910
2013-08-07    NaN
2013-08-08    NaN
2013-08-09    950
Freq: D, dtype: float64
我预计“2013-08-09”为930,或“2013-08-01”为88

In [12]: ts.Balance.resample('D', how='first')
Out[12]: 
Date
2013-08-01      87
2013-08-02     900
2013-08-03     NaN
2013-08-04     NaN
2013-08-05     NaN
2013-08-06     910
2013-08-07     NaN
2013-08-08     NaN
2013-08-09    1000
Freq: D, dtype: float64

我是不是遗漏了什么?使用“第一个”和“最后一个”重新采样是否没有达到我预期的效果?

问题在于,由于您的日期是重复的,因此实际上可能存在任意顺序;不保证使用DUP订购

In [24]: ts.Balance.resample('D',how='last')
Out[24]: 
Date
2013-08-01     87
2013-08-02    900
2013-08-03    NaN
2013-08-04    NaN
2013-08-05    NaN
2013-08-06    910
2013-08-07    NaN
2013-08-08    NaN
2013-08-09    930
Freq: D, dtype: float64

In [25]: ts.Balance.order().resample('D',how='last')
Out[25]: 
Date
2013-08-01      88
2013-08-02     900
2013-08-03     NaN
2013-08-04     NaN
2013-08-05     NaN
2013-08-06     910
2013-08-07     NaN
2013-08-08     NaN
2013-08-09    1000
Freq: D, dtype: float64
最简单的方法是对数据进行
排序
,但不清楚实际的排序是什么(例如,这里需要一个外部参数来决定它)

sort=False
传递给groupby(但重采样无法完成此操作)

你可以通过这种方式来得到你想要的东西

In [52]: df = DataFrame(ts.values,index=ts.index,columns=['values']).reset_index()

In [53]: df
Out[53]: 
                 Date  values
0 2013-08-09 00:00:00    1000
1 2013-08-09 00:00:00     950
2 2013-08-09 00:00:00     930
3 2013-08-06 00:00:00     910
4 2013-08-02 00:00:00     900
5 2013-08-01 00:00:00      88
6 2013-08-01 00:00:00      87

In [54]: df.groupby('Date').apply(lambda x: x.iloc[-1]['values']).reindex(date_range(ts.index.min(),ts.index.max()))

Out[54]: 
2013-08-01     87
2013-08-02    900
2013-08-03    NaN
2013-08-04    NaN
2013-08-05    NaN
2013-08-06    910
2013-08-07    NaN
2013-08-08    NaN
2013-08-09    930
Freq: D, dtype: float64

要能够对数据进行重新采样,首先必须对其进行排序。因此,如果加载数据并按索引对其进行排序,则会得到以下结果:

>>> pd.read_csv(data_string, parse_dates=[0], index_col=0).sort_index()
            Balance
Date               
2013-08-01       87
2013-08-01       88
2013-08-02      900
2013-08-06      910
2013-08-09     1000
2013-08-09      930
2013-08-09      950
这就解释了为什么你得到了你得到的结果@Jeff解释了为什么顺序是“任意的”,根据您的评论,解决方案是在操作之前对数据使用
mergesort
算法

>>> df = pd.read_csv(data_string, parse_dates=[0],
                     index_col=0).sort_index(kind='mergesort')
>>> df.Balance.resample('D',how='last')
2013-08-01      88
2013-08-02     900
2013-08-03     NaN
2013-08-04     NaN
2013-08-05     NaN
2013-08-06     910
2013-08-07     NaN
2013-08-08     NaN
2013-08-09    1000
>>> df.Balance.resample('D', how='first')
2013-08-01     87
2013-08-02    900
2013-08-03    NaN
2013-08-04    NaN
2013-08-05    NaN
2013-08-06    910
2013-08-07    NaN
2013-08-08    NaN
2013-08-09    930

对重复项的排序是任意的(例如,不保证合并或快速排序),IIRC@Jeff我以为是这样的。但是如果Pandas能够识别(在读取时)数据已经被排序(如本例中),并且只使用排序顺序,那将是一个非常好的功能。:)是的,我知道。。。这是一个“我不是小马”的请求:)请在github上提出请求;我不知道这有多棘手(在组索引计算中)。这个答案让我找到了解决方案,即使用.sort_index(kind='heapsort'),因为heapsort是一个稳定的排序算法,这意味着原始顺序将被保留。你能编辑你的答案来包含这个吗?根据这个维基百科页面,heapsort是不稳定的,所以正确的答案是使用稳定的kind='mergesort'。
>>> df = pd.read_csv(data_string, parse_dates=[0],
                     index_col=0).sort_index(kind='mergesort')
>>> df.Balance.resample('D',how='last')
2013-08-01      88
2013-08-02     900
2013-08-03     NaN
2013-08-04     NaN
2013-08-05     NaN
2013-08-06     910
2013-08-07     NaN
2013-08-08     NaN
2013-08-09    1000
>>> df.Balance.resample('D', how='first')
2013-08-01     87
2013-08-02    900
2013-08-03    NaN
2013-08-04    NaN
2013-08-05    NaN
2013-08-06    910
2013-08-07    NaN
2013-08-08    NaN
2013-08-09    930