【问题标题】:Sliding Window and comparing elements of DataFrame to a threshold滑动窗口并将 DataFrame 的元素与阈值进行比较
【发布时间】:2021-11-16 14:13:29
【问题描述】:

假设我有以下数据框:

Time  Flag1 
0      0        
10     0
30     0
50     1
70     1
90     0
110    0

我的目标是确定任何窗口内的时间是否小于让行中的数字加 35,然后如果标志的任何元素为 1,则该行将为 1。例如考虑上面的示例:

时间的第一个元素是 0 然后 0 + 35 = 35 然后在值小于 35 的窗口中(即 Time =0,10,30)所有 flag1 值都是 0 因此第一行将被分配给0 等等。那么下一个窗口将是 10 + 35 = 45 并且仍然会包括 (0,10,30) 并且标志仍然是 0。所以完整的输出是:

Time  Flag1   Output
0      0         0   
10     0         0
30     0         1
50     1         1
70     1         1
90     1         1
110    1         1

为了解决这类问题,我想我可以像这样使用两个 for 循环:

Output = []
for ii in range(Data.shape[0]):
       count =0
       th = Data.loc[ii,'Time'] + 35
       for jj in range(ii,Data.shape[0]):
           if (Data.loc[jj,'Time'] < th and Data.loc[jj,'Flag1'] == 1):
                  count = 1
                  break
       output.append(count)

但是这看起来很乏味。因为内部 for 循环应该继续为整个数据长度。另外,我不确定当我们到达数据帧的末尾时,此方法是否会检查边界情况是否超出索引。如果有人可以评论比这更容易的事情,我将不胜感激。这就像一个滑动窗口操作,只是将数字与阈值进行比较。

编辑:我不想只比较两个连续的行。我想如果例如 30 + 35 = 65 那么只要时间小于 65 则如果 flag1 为 1 则输出为 1。

第二个例子:

Time  Flag1   Output
0      0         0   
30     0         1
40     0         1
60     1         1
90     1         1
140    1         1
200    1         1
350    1         1

【问题讨论】:

  • 一个澄清问题:您提到了一个值/行窗口,其中似乎包括之前的 k 行和之后的 k 行(您的描述中的 k=1)。如果是这种情况,那么内部for 循环不应该是for jj in range(max(0, ii-1),min(ii+2, Data.shape[0]))吗?
  • 我不明白你之前所说的行是什么意思。我希望只要时间小于时间 + 阈值且 flag1 在此阈值内为 1,则输出为 1。输出值取决于阈值(因此为 35)和时间值。我想遍历时间值并检查时间是否小于时间+阈值,如果是,则检查 flag1 列,看看我在此持续时间内是否有 1,如果是,则输出为 1。
  • 我的问题旨在澄清当您在原始问题中谈论“窗口”时您的想法是:“如果在任何窗口内该时间小于让行中的数字加上 35 ”。无论如何,您可能想在下面查看我的答案。希望这能让你到达那里,如果没有,也许你可以简单地编辑你想要的索引和/或条件。

标签: python pandas dataframe loops sliding-window


【解决方案1】:

假设我的评论中提到了一个窗口 k 之前的行和 k 之后的行:

import pandas as pd

Data = pd.DataFrame([[0,0], [10,0], [30,0], [50,1], [70,1], [90,1], [110,1]],
                    columns=['Time', 'Flag1'])

k = 1   # size of window: up to k rows before and up to k rows after 
n = len(Data)
output = [0]*n
for i in range(n):
    th = Data['Time'][i] + 35
    j0 = max(0, i - k)
    j1 = min(i + k + 1, n)  # the +1 is because range is non-inclusive of end
    output[i] = int(any((Data['Time'][j0 : j1] < th) & (Data['Flag1'][j0 : j1] > 0)))
Data['output'] = output

print(Data)

提供与原始示例相同的输出。并且您可以更改窗口的大小我正在修改k

当然,如果想在之后检查任何行,那么在我的示例中只需使用 j1 = n

【讨论】:

    【解决方案2】:
    import pandas as pd
    
    Data = pd.DataFrame([[0,0],[10,0],[30,0],[50,1],[70,1],[90,1],[110,1]],columns=['Time','Flag1'])
    
    output = Data.index.map(lambda x: 1 if any((Data.Time[x+1:]<Data.Time[x]+35)*(Data.Flag1[x+1:]==1)) else 0).values
    output[-1] = Data.Flag1.values[-1]
    Data['output'] = output
    
    print(Data)
    
    # show
    Time    Flag1   output
    0       0       0
    30      0       1
    40      0       1
    50      1       1
    70      1       1
    90      1       1
    110     1       1
    

    【讨论】:

    • 它不起作用。你只是在比较两个连续的行。我想要的是如果 30 + 35= 65,那么如果任何时候小于 65,如果 flag1 列中有 1,那么我应该得到 1。
    • 已编辑,这次应该符合你的要求!
    • 这样逻辑就清楚了:例如,如果Data.Time[3:]中任意一个值小于30 + 35,Data.Time[3:]中任意一个值等于1,结果输出为1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多