按在 Pandas 中开始和结束的日期范围扩展行

Posted

技术标签:

【中文标题】按在 Pandas 中开始和结束的日期范围扩展行【英文标题】:Expand rows by date range having start and end in Pandas 【发布时间】:2019-12-22 19:59:54 【问题描述】:

我正在处理一个数据集,其中包含有关在某些时间范围内发生的现象的信息。我得到了事件的开始和结束时间及其严重性,以及一些其他信息。我想通过在设定的时间段内扩展行并将其余信息保留为 NaN 来在更大的时间段内扩展这些帧。

数据集示例:

                         date_end         severity   category
     date_start           
2018-01-04 07:00:00  2018-01-04 10:00:00     12          1
2018-01-04 12:00:00  2018-01-04 13:00:00     44          2

我想要的是:

                     severity   category
     date_start           
2018-01-04 07:00:00     12         1
2018-01-04 08:00:00     12         1
2018-01-04 09:00:00     12         1
2018-01-04 10:00:00     12         1
2018-01-04 11:00:00     nan       nan
2018-01-04 12:00:00     44         2
2018-01-04 13:00:00     44         2
2018-01-04 14:00:00     nan       nan
2018-01-04 15:00:00     nan       nan

实现这种结果的有效方法是什么?

【问题讨论】:

你是如何确定 date_start 范围的结束的? 这将是任意的,可以作为:datetime.datetime.now() 第一行的 end_date 是否应该是 10:00 而不是 7:00 每个预期输出?第二行的 date_start 应该是 2018-01-04 而不是 2018-01-05? 是的,很好,我在格式化方面犯了一个错误 第二个 date_start 是 2018-01-04 12:00:00 而不是 2018-01-05 12:00:00 【参考方案1】:

假设您使用的是 pandas v0.25,请使用 explode

df['hour'] = df.apply(lambda row: pd.date_range(row.name, row['date_end'], freq='H'), axis=1)
df = df.explode('hour').reset_index() \
        .drop(columns=['date_start', 'date_end']) \
        .rename(columns='hour': 'date_start') \
        .set_index('date_start')

对于带有nan 的行,您可以重新索引您的数据框。

# Report from Jan 4 - 5, 2018, from 7AM - 7PM
days = pd.date_range('2018-01-04', '2018-01-05')
hours = pd.to_timedelta(range(7, 20), unit='h')
tmp = pd.MultiIndex.from_product([days, hours], names=['Date', 'Hour']).to_frame()

s = tmp['Date'] + tmp['Hour']
df.reindex(s)

【讨论】:

关于重新索引的问题我使用了:date_range = pd.date_range(start=date_start, end=date_end, freq='H') df.reindex(date_range, fill_value=np.NaN),然后将 date_start 设置为 date_start 的最小值,并将 date_end 设置为任意值,您认为哪种解决方案效果更好 您的解决方案全天 24 小时提供报告。我的回答只在早上 7 点到晚上 7 点之间报告。两者都同样有效,但用途略有不同。 感谢您的澄清!格式也很抱歉,我还在努力解决【参考方案2】:

一种方法是使用 pd.date_range 重新索引 datafame,使用 ffill 并屏蔽索引大于 date_end 的值。

df.index = pd.to_datetime(df.index)

df['date_end'] = pd.to_datetime(df['date_end'])

df1 = df.reindex(pd.date_range(df.index.min(), '2018-01-04 15:00:00', freq='H'))

df1 = df1.ffill()

df1.loc[(df1.index - df1['date_end']) > pd.Timedelta(days=0)] = np.nan

df_out = df1.drop('date_end', axis=1)

print(df_out)

输出:

                     severity  category
2018-01-04 07:00:00      12.0       1.0
2018-01-04 08:00:00      12.0       1.0
2018-01-04 09:00:00      12.0       1.0
2018-01-04 10:00:00      12.0       1.0
2018-01-04 11:00:00       NaN       NaN
2018-01-04 12:00:00      44.0       2.0
2018-01-04 13:00:00      44.0       2.0
2018-01-04 14:00:00       NaN       NaN
2018-01-04 15:00:00       NaN       NaN

【讨论】:

以上是关于按在 Pandas 中开始和结束的日期范围扩展行的主要内容,如果未能解决你的问题,请参考以下文章

在熊猫中生成给定范围内的随机日期

在熊猫中传播范围日期

python中日期范围之间的月份开始日期和结束日期

Pandas - 将具有开始和结束日期的数据框转换为每日数据

pandas-对列中具有相同值的连续行进行分组和聚合

根据 Pandas DataFrame 中每个项目的开始和结束日期计算每月活动的项目数