【问题标题】:Fill in missing hours in a pandas dataframe在 pandas 数据框中填写缺失的小时数
【发布时间】:2018-09-19 15:46:10
【问题描述】:

我有一个包含每小时数据的数据框:

area     date         hour      output
H1       2018-07-01   07:00:00  150
H1       2018-07-01   08:00:00  150
H1       2018-07-01   09:00:00  100
H1       2018-07-01   11:00:00  150
H2       2018-07-01   09:00:00  100
H2       2018-07-01   10:00:00   50
H2       2018-07-01   11:00:00   50
H2       2018-07-01   12:00:00  150

但是数据只包含有输出时的小时数行,如何用输出 0 填充每个区域的缺失小时数?例如为 H1 添加两行:

area     date         hour      output
H1       2018-07-01   10:00:00  0
H1       2018-07-01   12:00:00  0

我可以假设所有区域的最小和最大小时是采样周期的开始和结束(在本例中为 7:00:00 和 12:00:00)

现在,我正在为每个区域创建一个包含从 7:00 到 12:00 的所有时间的数据框,然后将我的数据与该数据框合并,然后用 0 填充 NaN。这非常慢,因为我的数据集可能有数百万行。

有没有更好的方法?

【问题讨论】:

  • 你可以试试df.fillna(0)

标签: python pandas


【解决方案1】:

您可以检查resamplegroupby

df['Datetime']=pd.to_datetime(df.date+' '+df.hour)# combine hour and date to datetime 

df.drop(['date','hour'],inplace=True,axis = 1)# drop duplicate infomation
df.groupby('area').\
    apply(lambda x : x.set_index('Datetime').resample('H').mean().fillna(0)).\
      reset_index()
Out[662]: 
  area            Datetime  output
0   H1 2018-07-01 07:00:00   150.0
1   H1 2018-07-01 08:00:00   150.0
2   H1 2018-07-01 09:00:00   100.0
3   H1 2018-07-01 10:00:00     0.0
4   H1 2018-07-01 11:00:00   150.0
5   H2 2018-07-01 09:00:00   100.0
6   H2 2018-07-01 10:00:00    50.0
7   H2 2018-07-01 11:00:00    50.0
8   H2 2018-07-01 12:00:00   150.0

【讨论】:

    【解决方案2】:

    您可以创建一个最小值和最大值的日期范围,并将您的数据框与现有的数据框合并并使用 null 填充值

    df

        area    date    hour    output
    0   H1  2018-07-01 07:00:00 07:00:00    150
    1   H1  2018-07-01 08:00:00 08:00:00    150
    2   H1  2018-07-01 09:00:00 09:00:00    100
    6   H2  2018-07-01 11:00:00 11:00:00    50
    7   H2  2018-07-01 12:00:00 12:00:00    150
    
    df = pd.DataFrame(pd.date_range(pd.to_datetime(df['date'] +' ' + df['hour']).min(),pd.to_datetime(df['date'] +' ' + df['hour']).max(),freq='H'),columns= ['date']).merge(df,on=['date'],how='outer').fillna(0)
    df.hour = df.date.dt.strftime('%H:%M:%S')
    df.date = df.date.dt.strftime('%d-%m-%Y')
    df
    

    输出:

    date    area    hour    output
    0   01-07-2018  H1  07:00:00    150.0
    1   01-07-2018  H1  08:00:00    150.0
    2   01-07-2018  H1  09:00:00    100.0
    3   01-07-2018  0   10:00:00    0.0
    4   01-07-2018  H2  11:00:00    50.0
    5   01-07-2018  H2  12:00:00    150.0
    

    【讨论】:

      【解决方案3】:

      Wen 提出的解决方案只要来源日期/时间来自 单一测量日。

      如果源包含来自不同天的读数,则 resample 的结果 对于每个区域,从第一天最早的读数到最晚的读数 最后一天的阅读,包括中间夜间时间,什么是 可能不是你想要的。

      此解决方案的另一个缺点是它不提供“零”读数 从测量日的一开始,但从最早的读数开始。 这同样适用于“最终”阅读,也不一定在结尾 测量日。

      我的解决方案没有这些缺点,基于以下假设:

      1. 保留源日期 列,因为以后需要。 日期时间计算后,只删除小时列。
      2. 生成 df_borders DataFrame,其中包含 NaN 读数,用于开始/结束 测量日期,对于每个区域和日期,我假设为 07:00:0013:00:00
      3. 将上述 NaN 读数添加到主 DataFrame 并删除每个的重复项 区域 / 日期时间。这样,每个区域/天的源数据包含 每天的确切开始/结束的读数,无论是原始的还是添加的 df_borders.
      4. 为避免“非工作日”读数,必须在 ['区域','日期']。这就是为什么我将 date 栏留到现在。
      5. 现在 date 列不再需要,可以删除。
      6. 最后一步是打印结果。

      下面是示例程序:

      import pandas as pd
      
      df = pd.read_csv('Input.csv')
      
      # Generate df_borders - NaN readings for start / end of each area / date
      df_start = df[['area','date']].drop_duplicates()
      df_end = df_start.copy()
      df_start['hour'] = '07:00:00'
      df_end['hour'] = '13:00:00'
      df_borders = pd.concat([df_start,df_end])
      
      # Compute Datetime column and drop hour column, for both DataFrames
      df['Datetime'] = pd.to_datetime(df.date + ' ' + df.hour)
      df.drop('hour', inplace=True, axis = 1)
      df_borders['Datetime'] = pd.to_datetime(df_borders.date + ' ' + df_borders.hour)
      df_borders.drop('hour', inplace=True, axis = 1)
      
      # Add NaN readings
      df = df.append(df_borders, sort=False, ignore_index=True)\
          .drop_duplicates(subset=['area', 'Datetime'])
      
      # Generate the full set of readings
      df = df.groupby(['area', 'date'])\
          .apply(lambda x : x.set_index('Datetime').resample('H').mean().fillna(0))\
          .reset_index()
      df.drop('date', inplace=True, axis = 1)
      
      # Result
      print(df)
      

      有些部分是的解决方案的副本,以避免重新发明轮子。

      对于源数据:

      area,date,hour,output
      H1,2018-07-01,07:00:00,150
      H1,2018-07-01,08:00:00,120
      H1,2018-07-01,09:00:00,90
      H1,2018-07-01,11:00:00,130
      H2,2018-07-01,09:00:00,110
      H2,2018-07-01,10:00:00,50
      H2,2018-07-01,11:00:00,80
      H2,2018-07-01,12:00:00,110
      H2,2018-07-02,08:00:00,40
      H2,2018-07-02,09:00:00,65
      H2,2018-07-02,11:00:00,95
      H2,2018-07-02,12:00:00,45
      

      打印出来:

         area            Datetime  output
      0    H1 2018-07-01 07:00:00   150.0
      1    H1 2018-07-01 08:00:00   120.0
      2    H1 2018-07-01 09:00:00    90.0
      3    H1 2018-07-01 10:00:00     0.0
      4    H1 2018-07-01 11:00:00   130.0
      5    H1 2018-07-01 12:00:00     0.0
      6    H1 2018-07-01 13:00:00     0.0
      7    H2 2018-07-01 07:00:00     0.0
      8    H2 2018-07-01 08:00:00     0.0
      9    H2 2018-07-01 09:00:00   110.0
      10   H2 2018-07-01 10:00:00    50.0
      11   H2 2018-07-01 11:00:00    80.0
      12   H2 2018-07-01 12:00:00   110.0
      13   H2 2018-07-01 13:00:00     0.0
      14   H2 2018-07-02 07:00:00     0.0
      15   H2 2018-07-02 08:00:00    40.0
      16   H2 2018-07-02 09:00:00    65.0
      17   H2 2018-07-02 10:00:00     0.0
      18   H2 2018-07-02 11:00:00    95.0
      19   H2 2018-07-02 12:00:00    45.0
      20   H2 2018-07-02 13:00:00     0.0
      

      根据需要,一系列 7 个读数,用于 3 个区域/日期对。

      【讨论】:

        猜你喜欢
        • 2021-04-27
        • 2018-05-02
        • 1970-01-01
        • 2021-06-17
        • 1970-01-01
        • 1970-01-01
        • 2019-08-01
        • 2016-11-16
        相关资源
        最近更新 更多