【问题标题】:Efficiently generating labels for timeseries data based on future timeseries data根据未来的时间序列数据有效地为时间序列数据生成标签
【发布时间】:2020-11-26 04:08:56
【问题描述】:

我在 pandas 数据框中有两年的传感器数据。该指数是一个时间序列。看起来像这样:


                     temp1     overtemp  time_to_overtemp
datetime                                                    
2019-01-02 09:31:00  305.96
2019-01-02 09:32:00  305.98
2019-01-02 09:33:00  305.70
2019-01-02 09:34:00  305.30
2019-01-02 09:35:00  306.88

我想要做的是循环时间序列以填充“overtemp”和“time_to_overtemp”列。如果未来两周内任何时间的温度数据增加超过 2%,则需要为“overtemp”分配 1 . "time_to_overtemp" 需要显示下一个 >2% 读数的时间,如果它存在于接下来的两周内。如果温度在接下来的两周内显示在 2% 以内,则应为两列分配 0。

例如 2019-01-02 09:31:00 应该查看接下来两周的温度数据,并在两列中输入 0,因为该时间段内的所有数据都在值的 2% 以内。 2020-01-02 09:35:00 的过热值应该是 1,因为一周后该值增加了 5%。 time_to_overtemp 值应指示 7 天 2 小时 38 分钟,因为那是发生过热的时间。

我正在使用 iterrows 成功地做一些数学题:

for datetime, row in df.iterrows():

但它需要永远。而且我根本不知道如何进行时间迭代和计算。

我已经做了其他标签:

df['overtemp'] = np.select([df['temp1']<305, df['temp1']>305], [1,0])

我猜这将过程向量化?它确实比迭代快得多。但我不知道如何实现日期时间+两周部分。

【问题讨论】:

    标签: python pandas time-series


    【解决方案1】:

    以下是关于如何使用apply 和索引来解决您的问题的建议。

    但这确实不是一个很快的解决方案,也许熊猫有更好的功能来做到这一点。

    或者你可以parallelize the apply function 让它更快。

    df = pd.DataFrame(pd.date_range(start='2020-01-01', end='2020-03-01', freq='H'), columns=['datetime'])
    df['temp'] =  [np.random.uniform(low=300, high=310) for _ in range(df.shape[0])]
    
    def get_overtemp(row):
        now = row.datetime
        next_14_days = now + timedelta(days=14)
        temp = row.temp
        
        filtered = df[
            (df['datetime'] > now) & 
            (df['datetime'] <= next_14_days) & 
            (df['temp'] > temp * 1.02)
        ]
        
        overtemp = len(filtered) > 0
        time_to_overtemp = None
        if overtemp:
            time_to_overtemp = filtered['datetime'].values[0] - now
            
        return pd.Series([overtemp, time_to_overtemp])
    
    df[['overtemp', 'time_to_overtemp']] = df.apply(get_overtemp, axis=1)
    df.head(20)
    

    结果:

    |    | datetime            |    temp | overtemp   | time_to_overtemp   |
    |---:|:--------------------|--------:|:-----------|:-------------------|
    |  0 | 2020-01-01 00:00:00 | 309.502 | False      | NaT                |
    |  1 | 2020-01-01 01:00:00 | 303.816 | True       | 7 days 00:00:00    |
    |  2 | 2020-01-01 02:00:00 | 307.297 | False      | NaT                |
    |  3 | 2020-01-01 03:00:00 | 306.252 | False      | NaT                |
    |  4 | 2020-01-01 04:00:00 | 303.458 | True       | 0 days 07:00:00    |
    |  5 | 2020-01-01 05:00:00 | 304.27  | False      | NaT                |
    |  6 | 2020-01-01 06:00:00 | 300.98  | True       | 0 days 05:00:00    |
    |  7 | 2020-01-01 07:00:00 | 306.652 | False      | NaT                |
    |  8 | 2020-01-01 08:00:00 | 304.107 | False      | NaT                |
    |  9 | 2020-01-01 09:00:00 | 300.077 | True       | 0 days 02:00:00    |
    

    见:https://github.com/nalepae/pandarallel

    【讨论】:

    • 我明白你在做什么,但我想我现在有点困惑。您没有使用日期时间索引,所以我不确定您的 pd.Timedelta() 是如何正常运行的。感谢您抽出时间提供帮助。我将尝试对此进行扩展以使日期时间索引与之配合使用。
    • 我没有使用日期时间作为数据框索引。要执行与我的玩具示例相同的操作,只需运行 df = df.reset_index()。我使用的时间增量是from datetime import timedelta
    【解决方案2】:

    认为你可以通过应用 funcs 来实现 pandas 滚动,这是我的尝试,希望这是你需要的:

    # create random data
    ind = pd.date_range(start = pd.to_datetime("2019-01-02 09:31:00"), periods=28*24*60, freq='min')
    v = [random.randint(30000, 32000)/100 for x in ind]
    df = pd.DataFrame(v, index=ind, columns = ['temp1'])
    
    # define funcs
    def overtemp(S):
        l = S[S>=S[-1]*1.02]
        if len(l)>0:
            return l[-1]
        else:
            return 0
    
    def overtemp_seconds(S):
        l = np.argwhere(S.values>=S.values[-1]*1.02)
        if len(l)>0:
            i = l[-1][0]
            delta = S.index[i] - S.index[-1]
            return delta.seconds
        else:
            return 0
    
    # apply funcs to time window (reversed cause rolling gives you time window till offset)
    over_temp = df[::-1].rolling('14D').apply(overtemp)[::-1]['temp1']
    seconds_to_over_temp = df[::-1].rolling('14D').apply(overtemp_seconds)[::-1]['temp1']
    
    # add to orig df
    df['over_temp'] = over_temp
    df['seconds_to_over_temp'] = seconds_to_over_temp
    

    【讨论】:

    • 感谢您对此的帮助!这样可行!工作不快,哈哈,但我认为我不会快速解决这个问题。我将努力将其并行化,以至少在一定程度上缩短时间。另一个快速的问题,你对学习更多熊猫有什么建议吗?在过去的 6 个月里,我一直在研究我能想到的所有资源,并且觉得我应该能够自己处理这样的任务。显然我做不到。
    • 对资源没有任何具体的想法,抱歉。可以告诉你,我是从我的一个团队成员那里第一次听说滚动的,当我读到你的问题时,我猜想应该有一种方法可以在滚动窗口上应用用户定义的函数并在熊猫手册中寻找它,花了一些时间但我想了很多事情。认为要了解特定的高级 pandas 方法,应该阅读博客、问答等。
    猜你喜欢
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    相关资源
    最近更新 更多