簡體   English   中英

Pandas rolling_max,在df列中指定了可變窗口大小

[英]Pandas rolling_max with variable window size specified in a df column

我想計算一個pandas列的rolling_max,其中窗口大小不同,是當前行索引與滿足某個條件的行之間的差異。

所以,作為一個例子,我有:

df = pd.DataFrame({'a': [0,1,0,0,0,1,0,0,0,0,1,0],
                   'b': [5,4,3,6,1,2,3,4,2,1,7,8]})

我想要一個df.b的rolling_max,因為前一次df.a == 1。 即我想得到這個:

     a   b   rm
 0   0   5   NaN  <- no previous a==1
 1   1   4   4    <- a==1
 2   0   3   4
 3   0   6   6
 4   0   1   6
 5   1   2   2    <- a==1
 6   0   3   3
 7   0   4   4
 8   0   2   4
 9   0   1   4
10   1   7   7    <- a==1
11   0   8   8

我的df有一個沒有間隙的整數索引,所以我試着這樣做:

df['last_a'] = np.where(df.a == 1, df.index, np.nan)
df['last_a'].fillna(method='ffill', inplace=True)
df['rm'] = pd.rolling_max(df['b'], window = df.index - df['last_a'] + 1)

但我得到一個TypeError:需要一個整數。

這是在相當大的數據框架上運行的長腳本的一部分,因此我需要盡可能快的解決方案。 我已成功嘗試使用循環而不是rolling_max來執行此操作,但它非常慢。 能否請你幫忙?

僅供參考。 我現在擁有的丑陋和長循環,無論它的丑陋,在我的數據框架上看起來相當快(測試時為50,000 x 25),如下所示:

df['rm2'] = df.b
df['rm1'] = np.where( (df['a'] == 1) | (df['rm2'].diff() > 0), df['rm2'], np.nan)
df['rm1'].fillna(method = 'ffill', inplace = True)
df['Dif'] = (df['rm1'] - df['rm2']).abs()
while df['Dif'].sum() != 0:
    df['rm2'] = df['rm1']
    df['rm1'] = np.where( (df['a'] == 1) | (df['rm2'].diff() > 0), df['rm2'], np.nan) 
    df['rm1'].fillna(method = 'ffill', inplace = True)
    df['Dif'] = (df['rm1'] - df['rm2']).abs()

我會創建一個索引和groupby這個索引使用cummax

import numpy as np

df['index'] = df['a'].cumsum()
df['rm']    = df.groupby('index')['b'].cummax()

df.loc[df['index']==0, 'rm'] = np.nan

In [104]: df
Out[104]:
    a  b  index  rm
0   0  5      0 NaN
1   1  4      1   4
2   0  3      1   4
3   0  6      1   6
4   0  1      1   6
5   1  2      2   2
6   0  3      2   3
7   0  4      2   4
8   0  2      2   4
9   0  1      2   4
10  1  7      3   7
11  0  8      3   8

實際上,只要您需要重構涉及列和表之間關系的數據,請考慮使用關系數據庫管理系統(RDMS)的SQL解決方案。 如果您的數據來自數據庫,請特別注意。 讓Pandas進行數據分析。 當然,如果您要存儲的數據不在數據庫中,那么這就是另一個問題!

Python為SQLite提供了一個內置庫,這是一個流行的免費開源文件級數據庫。 此外,可以安裝MySQL,SQL Server,PostgreSQL,Oracle和其他RDMS的Python庫。 您可以將每個連接無縫集成到pandas中 以下是三個等效版本的查詢,以實現條件組最大值。 每個假定您在源表中維護一個自動編號主鍵索引ID ,此處稱為RollingMax

import sqlite3 as lite
import pandas as pd

con = lite.connect('C:\\Path\\SQLite\\DB.db')

# SQL WITH DERIVED TABLES
sql = """SELECT a, b,
               (SELECT Max(dtbl2.B) 
               FROM 
                   (SELECT t1.ID, t1.a, t1.b,
                          (SELECT Count(*) FROM RollingMax t2 
                           WHERE t1.ID >= t2.ID AND t2.A > 0) As GrpA
                    FROM RollingMax t1) dtbl2
               WHERE dtbl1.ID >= dtbl2.ID 
               AND dtbl1.GrpA = dtbl2.GrpA) As rm

         FROM 
         (
              SELECT t1.ID, t1.a, t1.b,
                     (SELECT Count(*) FROM RollingMax t2 
              WHERE t1.ID >= t2.ID AND t2.A > 0) As GrpA
              FROM RollingMax t1
         ) As dtbl1;"""

# SQL USING CTE WINDOW FUNCTION (AVAILABLE AS OF VERSION 3.8.3)
sql = """WITH grp (ID, a, b, GrpA)
         AS  (
              SELECT t1.ID, t1.a, t1.b,
                    (SELECT Count(*) FROM RollingMax t2 
                     WHERE t1.ID >= t2.ID AND t2.A > 0) As GrpA
              FROM RollingMax t1
             )
         SELECT a, b,
               (SELECT Max(dtbl2.B) 
                FROM grp AS dtbl2
                WHERE dtbl1.ID >= dtbl2.ID 
                AND dtbl1.GrpA = dtbl2.GrpA) As rm
         FROM grp AS dtbl1;"""

# SQL USING SAVED VIEW
'''To be saved inside database'''
saved_view = """SELECT t1.ID, t1.a, t1.b,
                  (SELECT Count(*) FROM RollingMax t2 
                   WHERE t1.ID >= t2.ID AND t2.A > 0) As GrpA
                FROM RollingMax t1;"""

sql = """SELECT a, b,
             (SELECT Max(dtbl2.B) 
              FROM saved_view AS dtbl2
              WHERE dtbl1.ID >= dtbl2.ID 
              AND dtbl1.GrpA = dtbl2.GrpA) As rm
         FROM saved_view As dtbl1;"""

df = pd.read_sql(sql, conn)

OUTPUT (這里唯一的挑戰是沒有前面的== 1的第一個分組)

a   b   rm
0   5   5
1   4   4
0   3   4
0   6   6
0   1   6
1   2   2
0   3   3
0   4   4
0   2   4
0   1   4
1   7   7
0   8   8

暫無
暫無

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

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