【问题标题】:How to resample daily data to hourly data for all whole days with pandas?如何使用熊猫将全天的每日数据重新采样为每小时数据?
【发布时间】:2020-07-10 17:33:33
【问题描述】:

我有一个数据框 df,如下所示:

    city    datetime    value
0   city_a  2020-07-10  2
1   city_a  2020-07-11  5
2   city_b  2020-07-11  4

我正在尝试以 6 小时的频率重新采样每日日期时间(数据每 00 小时、6 小时、12 小时和 18 小时)。

下面的代码给了我几乎我期望的输出

my_df = my_df.set_index(['datetime', 'city'])
my_df = my_df.unstack(-1).resample('6H').pad()
my_df = my_df.stack().reset_index()
my_df = my_df[['city', 'datetime', 'value']]
my_df = my_df.sort_values(['city', 'datetime'])

输出:

    city    datetime            value
0   city_a  2020-07-10 00:00:00 2.0
1   city_a  2020-07-10 06:00:00 2.0
2   city_a  2020-07-10 12:00:00 2.0
3   city_a  2020-07-10 18:00:00 2.0
4   city_a  2020-07-11 00:00:00 5.0
5   city_b  2020-07-11 00:00:00 4.0

但是,我们可以看到 2020-07-11 的日子并不完整。我希望包括 2020-07-11 06:00:00、12:00:00 和 18:00:00 在内的行出现在输出中。

所以我的预期输出应该是:

    city    datetime            value
0   city_a  2020-07-10 00:00:00 2.0
1   city_a  2020-07-10 06:00:00 2.0
2   city_a  2020-07-10 12:00:00 2.0
3   city_a  2020-07-10 18:00:00 2.0
4   city_a  2020-07-11 00:00:00 5.0
6   city_a  2020-07-11 06:00:00 5.0
8   city_a  2020-07-11 12:00:00 5.0
10  city_a  2020-07-11 18:00:00 5.0
5   city_b  2020-07-11 00:00:00 4.0
7   city_b  2020-07-11 06:00:00 4.0
9   city_b  2020-07-11 12:00:00 4.0
11  city_b  2020-07-11 18:00:00 4.0

Pandas 有没有优雅的方法?


生成数据框的代码:

my_df = pd.DataFrame(data = {
    'city': ['city_a', 'city_a', 'city_b'],
    'datetime': 
[pd.to_datetime('2020/07/10'),pd.to_datetime('2020/07/11'),pd.to_datetime('2020/07/11')],
    'value': [2,5,4]
})

【问题讨论】:

    标签: python pandas datetime


    【解决方案1】:

    使用:

    # STEP A
    df1 = (df.groupby('city')['datetime'].max() + pd.Timedelta(days=1)).reset_index()
    
    # STEP B
    df1 = pd.concat([df, df1]).set_index('datetime')
    
    # STEP C
    df1 = df1.groupby('city', as_index=False).resample('6H').ffill()
    
    # STEP D
    df1 = df1.reset_index().drop('level_0', 1).dropna(subset=['value'])
    

    详情:

    步骤 A:使用DataFrame.groupby 对city 上的数据帧进行分组以确定每个组中日期的最大值,并将1 day 添加到每个组的最大值,这将是重新采样数据帧所必需的。

    # print(df1)
         city   datetime
    0  city_a 2020-07-12
    1  city_b 2020-07-12
    

    STEP B:使用pd.concat将原始数据帧df连接到新创建的数据帧df1,这是因为我们必须在STEP C中重新采样数据帧。

    # print(df1)
                  city  value
    datetime                 
    2020-07-10  city_a    2.0
    2020-07-11  city_a    5.0
    2020-07-11  city_b    4.0
    2020-07-12  city_a    NaN
    2020-07-12  city_b    NaN
    

    步骤 C:使用 DataFrame.resample 以 6H 的频率对分组在 city 上的数据帧重新采样,并使用 ffill 向前填充值。

    # print(df1)
                             city  value
      datetime                          
    0 2020-07-10 00:00:00  city_a    2.0
      2020-07-10 06:00:00  city_a    2.0
      2020-07-10 12:00:00  city_a    2.0
      2020-07-10 18:00:00  city_a    2.0
      2020-07-11 00:00:00  city_a    5.0
      2020-07-11 06:00:00  city_a    5.0
      2020-07-11 12:00:00  city_a    5.0
      2020-07-11 18:00:00  city_a    5.0
      2020-07-12 00:00:00  city_a    NaN
    1 2020-07-11 00:00:00  city_b    4.0
      2020-07-11 06:00:00  city_b    4.0
      2020-07-11 12:00:00  city_b    4.0
      2020-07-11 18:00:00  city_b    4.0
      2020-07-12 00:00:00  city_b    NaN
    

    步骤 D:最后使用DataFrame.reset_index 并使用DataFrame.drop 沿axis=1 删除未使用的列,还使用DataFrame.dropna 删除列NaN 中具有NaN 值的行value。

    # print(df1)
                  datetime    city  value
    0  2020-07-10 00:00:00  city_a    2.0
    1  2020-07-10 06:00:00  city_a    2.0
    2  2020-07-10 12:00:00  city_a    2.0
    3  2020-07-10 18:00:00  city_a    2.0
    4  2020-07-11 00:00:00  city_a    5.0
    5  2020-07-11 06:00:00  city_a    5.0
    6  2020-07-11 12:00:00  city_a    5.0
    7  2020-07-11 18:00:00  city_a    5.0
    9  2020-07-11 00:00:00  city_b    4.0
    10 2020-07-11 06:00:00  city_b    4.0
    11 2020-07-11 12:00:00  city_b    4.0
    12 2020-07-11 18:00:00  city_b    4.0
    

    【讨论】:

    • @Shubham Sharma,谢谢!这就是我要找的!正如 jezrael 所说,一些解释会受到欢迎
    • @yoyoog 也请考虑我的回答,它可能更容易理解,但它给出了确切的预期输出:)
    • 超级,现在很好;)
    【解决方案2】:

    我看到的唯一方法是添加一个空行,其日期时间等于最新的现有日期时间 + 一天。然后你几乎可以做同样的事情(pivot 是替换 set_index 和 unstack 的便捷方法)。

    # adding a row where datetime corresponds to the max datetime + 1 day
    df.loc[len(df), 'datetime'] = df.datetime.max() + pd.Timedelta(days=1)
    
    # pivot to replace set_index & unstack
    df = (df.pivot(index='datetime', columns='city')
       .resample('6H')
       .pad(3)
       .stack()
       .reset_index()
       .sort_values(['city', 'datetime']))
    
    df[['city', 'datetime', 'value']]
    
        city    datetime    value
    0   city_a  2020-07-10 00:00:00 2.0
    1   city_a  2020-07-10 06:00:00 2.0
    2   city_a  2020-07-10 12:00:00 2.0
    3   city_a  2020-07-10 18:00:00 2.0
    4   city_a  2020-07-11 00:00:00 5.0
    6   city_a  2020-07-11 06:00:00 5.0
    8   city_a  2020-07-11 12:00:00 5.0
    10  city_a  2020-07-11 18:00:00 5.0
    5   city_b  2020-07-11 00:00:00 4.0
    7   city_b  2020-07-11 06:00:00 4.0
    9   city_b  2020-07-11 12:00:00 4.0
    11  city_b  2020-07-11 18:00:00 4.0
    

    【讨论】:

    • 您正在考虑整个日期时间列的最大值,但我认为我们必须按组考虑日期时间的最大值。
    • @ShubhamSharma 是的,你是对的,我的示例非常具有误导性,因为两个组的最大日期相同,但可能不同
    • 我已经测试了代码,例如,当我们在 df 中将 city_b 日期更改为 2020-07-13 然后结果我们有记录 city_a 日期为 2020-07-12 这是不正确的.也许应该为每个组添加最大日期。
    • @ShubhamSharma @yoyoog 检查枢轴的样子,您会看到它包含datetime 中的所有日期。 @ipj 此行为是由pad 函数引起的。我通过设置限制为 3 进行编辑,我们确保填充不超过 3 行(对应于 6、12 和 18h)
    • 现在在更改为.pad(3) 并在df 更改city_b 日期为2020-07-13 之后,city_b 中每6H 没有记录:-)
    猜你喜欢
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 2020-09-19
    • 2018-04-25
    • 2023-03-19
    相关资源
    最近更新 更多