簡體   English   中英

Pandas - 滾動窗口 - CustomIndex - 右邊界不包括在總和窗口中

[英]Pandas - Rolling window - CustomIndex - right bound is not included in window for sum

我發現了 CustomIndexer,我可以看到“結束”(左邊界)不包含在我想要做的后續總和中。

這會導致2個問題:

  • 總和未在我想要的行上實現

  • 無法正確管理DataFrame的第一行(因為,該窗口不是帶有單個單元格的窗口,而是一個空窗口)

為了解決第一個后果,我采用了包含下一行以確保窗口在我希望它結束​​的地方結束。

但是,對於第二個問題,我沒有退路。

原始代碼

所以我在一個單獨的函數中測試了我的第一個自定義窗口以簡化調試。

import pandas as pd
import numpy as np

def custom_bounds(num_values, index, date_range):
    start = np.empty(num_values, dtype=np.int64)
    end = np.empty(num_values, dtype=np.int64)        
    ind_as_int = index.to_series().reset_index(drop=True) 
    dr_as_series = date_range.to_series()
    # 1st item is skipped and default to 0
    start[0]=0
   end[0]=0
    # Loop for other items
    for i in range(num_values)[1:]:
        previous_ts_in_dr = dr_as_series.loc[dr_as_series.index < ind_as_int.iat[i]].index[-1]
        start[i] = ind_as_int.loc[ind_as_int >= previous_ts_in_dr].index[0]
        end[i] = i-1
return start, end

輸入數據為例

我可以使用以下輸入值對其進行測試。

from random import seed
from random import randint

# DataFrame
ts_1h = pd.date_range(start='2020-01-01 00:00+00:00', end='2020-01-02 00:00+00:00', freq='1h')
seed(1)
values = [randint(0,10) for ts in ts_1h]
df = pd.DataFrame({'Values' : values}, index=ts_1h)
df.index.name='Timestamp'

# Processing
dr = pd.date_range(start='2019-12-31 23:00+00:00', end='2020-01-03 00:00+00:00', freq='3h')

運行它:

In [20]: df.head(4)
Out[20]: 
                           Values
Timestamp                                   
2020-01-01 00:00:00+00:00       2
2020-01-01 01:00:00+00:00       9
2020-01-01 02:00:00+00:00       1
2020-01-01 03:00:00+00:00       4

使用輸入數據運行原始代碼

start, end = custom_bounds(num_values=df.shape[0], index=df.index, date_range=dr)

df_2 = pd.DataFrame({'int' : df.reset_index().index,
                 'start' : start,
                 'end' : end},
                index = df.index)
df_2.loc[df_2.index.isin(dr), 'TS_3h'] = 'X'

所以基本上,在 df_2 中,我們可以看到標記自定義窗口開始和結束的整數。 這兩個邊界都必須包含在滾動窗口中。 我對您可以閱讀的值感到滿意。

In [22]: df_2.head(6)
Out[22]: 
                           int  start  end TS_3h
Timestamp                                       
2020-01-01 00:00:00+00:00    0      0    0   NaN
2020-01-01 01:00:00+00:00    1      0    0   NaN
2020-01-01 02:00:00+00:00    2      0    1     X
2020-01-01 03:00:00+00:00    3      2    2   NaN
2020-01-01 04:00:00+00:00    4      2    3   NaN
2020-01-01 05:00:00+00:00    5      2    4     X

所以我對下一步充滿信心。 我打算看到以下總和:

  • 對於第 1 行 (int 0),其實際值:2
  • 對於第 2 行 (int 1),第 1 行的值:2
  • 對於第 3 行(int 2),第 1 行和第 2 行值的總和:11

實現 CustomIndexer 並運行它

所以我將我的代碼集成到自定義的“get_window_bounds()”中,如下所示。

from pandas.api.indexers import BaseIndexer


class CustomIndexer(BaseIndexer):

    def get_window_bounds(self, num_values, min_periods, center, closed):
        start = np.empty(num_values, dtype=np.int64)
        end = np.empty(num_values, dtype=np.int64)        
        ind_as_int = self.index.to_series().reset_index(drop=True) 
        dr_as_series = self.date_range.to_series()
        # 1st item is skipped and default to 0
        start[0]=0
        end[0]=0
        # Loop for other items
        for i in range(num_values)[1:]:
            previous_ts_in_dr = dr_as_series.loc[dr_as_series.index < ind_as_int.iat[i]].index[-1]
            start[i] = ind_as_int.loc[ind_as_int >= previous_ts_in_dr].index[0]
            end[i] = i-1
        return start, end

indexer = CustomIndexer(index=df.index, date_range=dr, closed='both')
df['Sum'] = df.rolling(indexer).sum()
df.loc[df.index.isin(dr), 'TS_3h'] = 'X'

運行它:

In [25]: df.head(4)
Out[25]: 
                           Values  Sum TS_3h
Timestamp                                   
2020-01-01 00:00:00+00:00       2  0.0   NaN
2020-01-01 01:00:00+00:00       9  0.0   NaN
2020-01-01 02:00:00+00:00       1  2.0     X
2020-01-01 03:00:00+00:00       4  0.0   NaN

如上所述,我打算看到以下結果:

  • 對於第 1 行 (int 0),其實際值:2
  • 對於第 2 行 (int 1),第 1 行的值:2
  • 對於第 3 行(int 2),第 1 行和第 2 行值的總和:11

所以問題是:我如何確保正確的界限包含在總和的計算中?

謝謝你的幫助。

好的,通過干預索引解決了。 抱歉打擾了。

    def get_window_bounds(self, num_values, min_periods, center, closed):
        start = np.empty(num_values, dtype=np.int64)
        end = np.empty(num_values, dtype=np.int64)        
        ind_as_int = self.index.to_series().reset_index(drop=True) 
        dr_as_series = self.date_range.to_series()
        # Loop over items
        for i in range(num_values):
            previous_ts_in_dr = dr_as_series.loc[dr_as_series.index < ind_as_int.iat[i]].index[-1]
            start[i] = ind_as_int.loc[ind_as_int >= previous_ts_in_dr].index[0]
            end[i] = i
        # Correct end[0]
        end[0]=1
        return start, end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM