【问题标题】:Resampling Within a Pandas MultiIndex Loses Values在 Pandas MultiIndex 中重新采样会丢失值
【发布时间】:2021-08-21 15:57:12
【问题描述】:

我有一些从 2003 年到 2011 年的分层数据,这些数据最终形成时间序列数据,看起来像这样:

polar_temp
         Station_Number      Date  Value
417         CA002100805  20030101   -296
423         CA002202570  20030101   -269
425         CA002203058  20030101   -268
427         CA002300551  20030101    -23
428         CA002300902  20030101   -200

我在 Station_Number 和 Date 上设置了多重索引:

polar_temp['Date'] = pd.to_datetime(polar_temp['Date'],
                     format='%Y%m%d')#.dt.strftime("%Y-%m-%d")
polar_temp = polar_temp.set_index(['Station_Number', "Date"])

                           Value
Station_Number Date             
CA002100805    2003-01-01   -296
CA002202570    2003-01-01   -269
CA002203058    2003-01-01   -268
CA002300551    2003-01-01    -23
CA002300902    2003-01-01   -200

现在我想通过使用以下方法计算每 8 天的 Value 的平均值来对数据进行重新采样:

polar_temp8d = polar_temp.groupby([pd.Grouper(level='Station_Number'),
                                    pd.Grouper(level='Date', freq='8D')]).mean()

                                Value
Station_Number Date                  
CA002100805    2003-01-01 -300.285714
               2003-01-09 -328.750000
               2003-01-17 -325.500000
               2003-01-25 -385.833333
               2003-02-02 -194.428571
...                               ...
USW00027515    2005-06-23   76.625000
               2005-07-01   42.375000
               2005-07-09   94.500000
               2005-07-17   66.500000
               2005-07-25   56.285714

所以这里的问题是 pandas 只对 2003 年到 2005 年的年份进行重新采样,所以 2006 年到 2011 年的年份完全被忽略了。现在我的问题是:我是使用 Grouper 函数正确分析时间序列数据还是我遗漏了什么?

编辑 1:

通过运行:

print(polar_temp.loc['CA002300902'].sort_index(ascending=False))

            Value
Date             
2011-12-31   -288
2011-12-30   -299
2011-12-29   -347
2011-12-28   -310
2011-12-27   -239

可以看到重采样前的台站有到2011年的数据。

【问题讨论】:

  • 某些台站2005年以后没有数据吗?我相信汇总只会包括有车站数据的时期。
  • 但是对于有 2003 年到 2011 年数据的站点,聚合仍然应该运行,因为据我了解,pandas 会明智地运行重采样站。
  • 您能否通过运行df.loc[STATION_WITH_LATER_DATA'].sort_index(ascending=False) 再次检查。另外,我认为这不会产生影响,但polar_temp.groupby(['Station Number', pd.Grouper(level='Date', freq='8D')]) 足以进行分组操作。
  • 感谢您要求我仔细检查,因为对于某些站点,重新采样在整个时间段内都有效,但是行数下降到 60.000 左右,而应该在 300.000 左右
  • 我又检查了一遍,甚至有几年的数据空白,这不可能是真的。

标签: python pandas time-series multi-index


【解决方案1】:

我创建了合成数据来测试您的方法,并且效果很好。 然后,我任意删除了数据点,以查看聚合是否会因缺少日期而失败,并且它会跳过时间序列中的缺失值,如下面的输出所示。因此,我仍然不明白为什么您的输出在 2005 年停止。

没有重采样和插值的输出:

                                Value
Station_Number Date                  
CA002100805    2003-01-02 -195.545455
               2003-01-10 -144.963636
               2003-01-18 -158.045455
               2003-01-26 -151.533333
               2003-02-03 -196.300000
               2003-04-08 -159.963636
               2003-04-16 -157.115385
               2003-04-24 -150.191489
               2003-05-02 -146.113924
               2003-05-10 -133.367347

注意它是如何完全跳过 2003 年 3 月的数据点的。

您可以通过以下方式对问题进行排序: 1.Adding missing dates to the DataFrame 2. 用interpolate()填充NAs

import pandas as pd
import numpy as np

# Sets random seed
np.random.seed(42)

# Sample size
size=10**5

station_numbers = ['CA002100805', 'CA002202570', 'CA002203058', 'CA002300551',
                   'CA002300902']

stations = [station_numbers[i] for i in
            np.random.randint(low=0, high=len(station_numbers), size=size)]

values = np.random.randint(low=-400, high=100, size=size)

dates_list = pd.date_range(start='2003-01-01', end='2011-12-31')

###################################
#### TESTS with missing dates #####
###################################

# Removes dates from dates_list to test
percent_to_remove = 1/3
items_to_remove = len(dates_list) * percent_to_remove

# Index of items to remove
rem_idx = set()
while len(rem_idx) < items_to_remove:
    # Thanks to Jon Kiparsky's answer on this thread
    # https://stackoverflow.com/questions/28037158/how-to-not-repeat-randint-value
    rem_idx.add(np.random.randint(0, len(dates_list)))

dates_list = dates_list.delete(list(rem_idx))

# Arbitratily removes dates in sequence to test
dates_list = dates_list.delete(range(20, 60))

###################################
###################################

dates = [dates_list[i] for i in
         np.random.randint(low=0, high=len(dates_list), size=size)]

# Creates DataFrame
data = (pd.DataFrame({'Station_Number': stations,
                     'Date': dates,
                     'Value': values})
        .set_index('Date')
        .sort_index())

# Creates one row per day
data = data.groupby('Station_Number').resample('D').mean()

# Fills NAs with standard interpolation strategy
data = data.interpolate()

# Calculates 8-day mean value
eight_day_mean = data.groupby([pd.Grouper(level='Station_Number'),
                               pd.Grouper(level='Date', freq='8D')]).mean()

重采样和插值输出:

                                Value
Station_Number Date                  
CA002100805    2003-01-02 -178.138024
               2003-01-10 -135.644524
               2003-01-18 -147.253977
               2003-01-26 -147.694712
               2003-02-03 -200.642180
               2003-02-11 -203.057708
               2003-02-19 -192.821042
               2003-02-27 -182.584375
               2003-03-07 -172.347708
               2003-03-15 -162.111042
               2003-03-23 -151.874375
               2003-03-31 -141.637708
               2003-04-08 -154.028469
               2003-04-16 -151.099405
               2003-04-24 -156.152083

现在请注意,由于采用了插值策略,它包含 2003 年 3 月的数据点,这些数据点介于 2003 年 2 月和 2003 年 4 月的值之间。

【讨论】:

  • 这是一个非常好的方法,但不幸的是我不允许插入数据。我也想过添加缺失的日期,但无法想出一个探索者的想法。
  • 您可以跳过插值,最终数据集将在没有数据的地方显示 NA。让我知道它是否有效。如果是这样,如果您接受答案并投赞成票,我将不胜感激。
  • 我会的,谢谢你的帮助!我只是在努力将缺失的日期添加到 df 中。我的方法是只创建一个空的df,其中df具有站点数据的时间段日期,以用NaN填充数据空白。我用过:for station, gp in polar_temp.groupby('Station_Number'): station_merge = pd.merge(gp, df, on=['Date'], how='outer') polar_m = pd.concat([station_merge, polar_merge], axis=0) polar_m['Station_Number'] = station
  • 为什么不使用我上面发布的重采样方法? data = data.groupby('Station_Number').resample('D').mean()
  • 我不太确定如何将每个站的值传递到您的脚本中。抱歉所有问题,你可以猜到我对 Python 很陌生
猜你喜欢
  • 2013-03-25
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-20
  • 2020-07-20
  • 1970-01-01
  • 2020-02-02
相关资源
最近更新 更多