【问题标题】:Unexpected number of bins in Pandas DataFrame resamplePandas DataFrame 重新采样中的 bin 数量意外
【发布时间】:2020-11-06 07:06:32
【问题描述】:

问题

我需要将 DataFrame 的长度减少到某个外部定义的整数(可以是两行、10,000 行等,但总是会减少总长度),但我也希望保留生成的 DataFrame 代表原来的。原始 DataFrame(我们称之为df)有一个datetime 列(utc_time)和一个数据值列(data_value)。日期时间始终是连续的、不重复的,尽管间隔不均匀(即,数据可能“丢失”)。对于本例中的 DataFrame,时间戳以十分钟为间隔(当数据存在时)。

尝试

为了做到这一点,我立即想到了用以下逻辑进行重采样:找出第一个时间戳和最后一个时间戳之间的秒差,将其除以所需的最终长度,这就是重采样因子。我在这里设置:

# Define the desired final length.
final_length = 2
# Define the first timestamp.
first_timestamp = df['utc_time'].min().timestamp()
# Define the last timestamp.
last_timestamp = df['utc_time'].max().timestamp()
# Define the difference in seconds between the first and last timestamps.
delta_t = last_timestamp - first_timestamp
# Define the resampling factor.
resampling_factor = np.ceil(delta_t / final_length)

# Set the index from the `utc_time` column so that we can resample nicely.
df.set_index('utc_time', drop=True, inplace=True)
# Do the resampling.
resamp = df.resample(f'{resampling_factor}S')

查看resamp,我只是循环打印:

for i in resamp:
    print(i)

这产生了(在我方面进行了一些清理)以下内容:

 utc_time                  data_value
 2016-09-28 21:10:00       140.0
 2016-09-28 21:20:00       250.0
 2016-09-28 21:30:00       250.0
 2016-09-28 21:40:00       240.0
 2016-09-28 21:50:00       240.0
 ...                         ...
 2018-08-06 13:00:00       240.0
 2018-08-06 13:10:00       240.0
 2018-08-06 13:20:00       240.0
 2018-08-06 13:30:00       240.0
 2018-08-06 13:40:00       230.0
 
 [69889 rows x 1 columns])

 utc_time                  data_value
 2018-08-06 13:50:00       230.0
 2018-08-06 14:00:00       230.0
 2018-08-06 14:10:00       230.0
 2018-08-06 14:20:00       230.0
 2018-08-06 14:30:00       230.0
 ...                         ...
 2020-06-14 02:50:00       280.0
 2020-06-14 03:00:00       280.0
 2020-06-14 03:10:00       280.0
 2020-06-14 03:20:00       280.0
 2020-06-14 03:30:00       280.0
 
 [97571 rows x 1 columns])

 utc_time                  data_value
 2020-06-14 03:40:00       280.0
 2020-06-14 03:50:00       280.0
 2020-06-14 04:00:00       280.0
 2020-06-14 04:10:00       280.0
 2020-06-14 04:20:00       280.0
 ...                         ...
 2020-06-15 00:10:00       280.0
 2020-06-15 00:20:00       270.0
 2020-06-15 00:30:00       270.0
 2020-06-15 00:40:00       270.0
 2020-06-15 00:50:00       280.0

 [128 rows x 1 columns])

如您所见,这产生了三个垃圾箱,而不是我预期的两个。

我可以做一些不同的事情,比如改变我选择重采样因子的方式(例如,找到时间戳之间的平均时间,并将其乘以(DataFrame 的长度/final_length)应该会产生一个更保守的重采样因子),但在我看来,这将掩盖根本问题。主要是,我很想了解为什么会发生这种情况。这导致...

问题

有谁知道为什么会发生这种情况,以及我可能会采取哪些步骤来确保我们获得所需数量的垃圾箱?我想知道这是否是一个偏移问题 - 也就是说,虽然我们将第一个 bin 中的第一个时间戳视为 DataFrame 中的第一个时间戳,但也许 pandas 实际上是在此之前开始 bin 的?

对于任何想在家一起玩的人,测试 DataFrame 可以是 found here 格式的 .csv。将其作为 DataFrame 获取:

df = pd.read_csv('test.csv', parse_dates=[0])

【问题讨论】:

    标签: python python-3.x pandas dataframe resampling


    【解决方案1】:

    总结

    • 问题 1 和修复:您形成垃圾箱的方式会产生一个额外的垃圾箱,因为使用df.resample() 创建的垃圾箱将是仅在一端(左侧或右侧)关闭。使用“1”中列出的选项之一修复此问题。

    • 问题 2 和修复:第一个 bin 左边缘位于当天开始时 ('2016-09-28 00:00:00')(参见“2.”)。您可以使用kind='period' 作为resample() 的参数来修复它。 (见“3”)

    1。浏览输入数据(以及我们需要什么样的 bin)

    输入数据是从2016-09-28 21:10:002020-06-15 00:50:00,使用你有的resampling_factor,我们得到:

    In [63]: df.index.min()
    Out[63]: Timestamp('2016-09-28 21:10:00')
    
    In [64]: df.index.min() + pd.Timedelta(f'{resampling_factor}S')
    Out[64]: Timestamp('2018-08-07 11:00:00')
    
    In [65]: _ + pd.Timedelta(f'{resampling_factor}S')
    Out[65]: Timestamp('2020-06-15 00:50:00')
    

    要使用这些时间戳将数据分成两部分,我们需要将 bin 分类

    • ['2016-09-28 21:10:00', '2018-08-07 11:00:00')
    • ['2018-08-07 11:00:00', '2020-06-15 00:50:00']

    [ 表示封闭端,( 表示开放端)

    • 这里有一个问题:您不能形成两端封闭的垃圾箱。您必须决定是从左侧还是从右侧关闭垃圾箱(参数closed='left'|'right',)。使用closed='left',您将拥有
      • ['2016-09-28 21:10:00', '2018-08-07 11:00:00')
      • ['2018-08-07 11:00:00', '2020-06-15 00:50:00')
      • ['2020-06-15 00:50:00', '2022-04-23 14:40:00') (这里只有一个条目)

    可能的修复

    1. 通过添加一些时间来调整您的最后一个时间戳:
        last_timestamp = (df['utc_time'].max() +
                          pd.Timedelta('10 minutes')).timestamp()
    
    1. 使resampling_factor 比您最初计算的要大一点。
    2. 只使用df.resample 中的前两个数据帧,忽略只有一个或几个条目的第三个数据帧

    选择对您的应用最有意义的选项。

    2。看看我们现在所拥有的

    • df.resample 文档中,我们知道返回的标签是左侧 bin 边缘
    • 如果我们查看数据,我们会看到现在有什么样的标签。
    
    In [67]: resamp = df.resample(f'{resampling_factor}S')
    
    In [68]: itr = iter(resamp)
    
    In [69]: next(itr)
    Out[69]:
    (Timestamp('2016-09-28 00:00:00', freq='58542600S'),
                          data_value
     utc_time
     2016-09-28 21:10:00       140.0
     ...                         ...
     2018-08-06 13:40:00       230.0
    
     [69889 rows x 1 columns])
    
    In [70]: next(itr)
    Out[70]:
    (Timestamp('2018-08-06 13:50:00', freq='58542600S'),
                          data_value
     utc_time
     2018-08-06 13:50:00       230.0
     ...                         ...
     2020-06-14 03:30:00       280.0
    
     [97571 rows x 1 columns])
    
    In [71]: next(itr)
    Out[71]:
    (Timestamp('2020-06-14 03:40:00', freq='58542600S'),
                          data_value
     utc_time
     2020-06-14 03:40:00       280.0
     ...                         ...
     2020-06-15 00:50:00       280.0
    
     [128 rows x 1 columns])
    
    
    • 因此垃圾箱是
      • ['2016-09-28 00:00:00', '2018-08-06 13:50:00')
      • ['2018-08-06 13:50:00', '2020-06-14 03:40:00')
      • ['2020-06-14 03:40:00', '2022-04-22 17:30:00') (通过将resampling_factor 添加到 bin 的开头来计算端点。)
    • 我们看到第一个 bin 不是从 df['utc_time'].min (2016-09-28 21:10:00) 开始的,而是从那天开始开始(如您所料)
    • 由于第一个 bin 比预期的开始,我们有两个 bin 之外的数据,在 第三个​​ bin 中。

    3。固定起始 bin 左边缘

    kind 参数可以是 'timestamp''period'。如果您将其更改为'period',您将拥有以下垃圾箱(带有closed='left'):

    • ['2016-09-28 21:10:00', '2018-08-07 11:00:00')
    • ['2018-08-07 11:00:00', '2020-06-15 00:50:00')
    • ['2020-06-15 00:50:00', '2022-04-23 14:40:00')(使用“1”中给出的选项删除)

    【讨论】:

    • 这是一个非常全面的答案。我不知道 kind 参数也改变了 bin 的定义方式!文档根本没有说清楚(或者我极大地误解了它们)。谢谢!
    • 谢谢!很高兴回答一个定义明确并且有示例数据可供使用的问题。我还不得不花一些时间来弄清楚它是如何工作的。我同意,目前没有太多的文档记录。
    猜你喜欢
    • 2013-12-06
    • 1970-01-01
    • 2017-01-14
    • 2012-08-24
    • 2013-11-22
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多