【问题标题】:How to determine data capture with a pandas dataframe?如何使用 pandas 数据框确定数据捕获?
【发布时间】:2016-06-11 17:33:14
【问题描述】:

我正在处理由不完整的时间序列组成的每小时监控数据,即我的数据框中将缺少一年(或几年)中的几个小时。

我想确定数据捕获,即一个月、一个季节或一年中存在的值的百分比。

这适用于以下代码(用于为每月重采样编写的演示) - 但是那段代码似乎效率低下,因为我需要创建第二个每小时数据帧并且我需要重新采样两个数据帧。

有没有更优雅的解决方案?

import numpy as np
import pandas as pd

# create dummy series
t1 = pd.date_range(start="1997-01-01 05:00", end="1997-04-25 17:00", freq="H")
t2 = pd.date_range(start="1997-06-11 15:00", end="1997-06-15 12:00", freq="H")
t3 = pd.date_range(start="1997-06-18 00:00", end="1997-08-22 23:00", freq="H")

df1 = pd.DataFrame(np.random.randn(len(t1)), index=t1)
df2 = pd.DataFrame(np.random.randn(len(t2)), index=t2)
df3 = pd.DataFrame(np.random.randn(len(t3)), index=t3)

df = pd.concat((df1, df2, df3))

# create time index with complete hourly coverage over entire years
tstart = "%i-01-01 00:00"%(df.index.year[0])
tend = "%i-12-31 23:00"%(df.index.year[-1])
tref = pd.date_range(start=tstart, end=tend, freq="H")
dfref = pd.DataFrame(np.zeros(len(tref)), index=tref)

# count number of values in reference dataframe and actual dataframe
# Example: monthly resampling
cntref = dfref.resample("MS", "count")
cnt = df.resample("MS", "count").reindex(cntref.index).fillna(0)

for i in range(len(cnt.index)):
    print cnt.index[i], cnt.values[i], cntref.values[i], cnt.values[i] / cntref.values[i]

【问题讨论】:

    标签: python pandas resampling


    【解决方案1】:

    pandas'Timedelta 可以解决问题:

    # Time delta between rows of the df
    df['index'] = df.index
    pindex = df['index'].shift(1)
    delta = df['index'] - pindex
    
    # Any delta > 1H means a missing data period
    missing_delta = delta[delta > pd.Timedelta('1H')]
    
    # Sum of missing data periods divided by total period
    ratio_missing = missing_delta.sum() / (df.index[-1] - df.index[0])
    

    【讨论】:

    • 这个解决方案既有趣又快速,但不幸的是并没有达到我想要的效果,因为我需要每个月的数据捕获,而不仅仅是总分数。但是很高兴了解 Timedelta。
    【解决方案2】:

    您可以使用 TimeGrouper。

    # Create an hourly index spanning the range of your data.
    idx = pd.date_range(pd.Timestamp(df.index[0].strftime('%Y-%m-%d %H:00')), 
                        pd.Timestamp(df.index[-1].strftime('%Y-%m-%d %H:00')), 
                        freq='H')
    
    # Use TimeGrouper to calculate the fraction of observations from `df` that are in the 
    # hourly time index.
    >>> (df.groupby(pd.TimeGrouper('M')).size() / 
         pd.Series(idx).reindex(idx).groupby(pd.TimeGrouper('M')).size())
    1997-01-31    1.000000
    1997-02-28    1.000000
    1997-03-31    1.000000
    1997-04-30    0.825000
    1997-05-31    0.000000
    1997-06-30    0.563889
    1997-07-31    1.000000
    1997-08-31    1.000000
    Freq: M, dtype: float64
    

    【讨论】:

    • 这行得通(如果我在上面的示例中调整代码以将 idx 计算为tref)。但是,在我的计算机上,它需要的时间大约是原始解决方案的两倍。分组似乎天生就很慢 - 如果分组或操作更复杂,它的优势可能会得到回报。
    【解决方案3】:

    由于没有进一步的建议,看来最初发布的解决方案似乎是最有效的。

    【讨论】:

      【解决方案4】:

      不确定性能,但是对于(非常长的)一个班轮,您可以在创建“df”后执行此操作......它至少具有不需要虚拟数据框的好处。它应该适用于任何时期的数据输入和重新采样。

      month_counts = df.resample('H').mean().resample('M').count() / df.resample('H').ffill().fillna(1).resample('M').count()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-11-18
        • 2015-01-21
        • 2021-11-02
        • 2019-12-28
        • 1970-01-01
        • 2015-06-18
        • 1970-01-01
        相关资源
        最近更新 更多