在df列中指定可变窗口大小的Pandas rolling_max

2024-09-27 23:15:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我想计算pandas列的滚动最大值,其中窗口大小不同,是当前行索引与满足特定条件的行之间的差异。在

作为一个例子,我有:

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的滚动最大值,因为上次df.a==1。一、 我想得到这个:

^{pr2}$

我的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)

但是我得到了一个类型错误:需要一个整数。在

这是在相当大的数据帧上运行的长脚本的一部分,所以我需要最快的解决方案。我已经成功地尝试用一个循环来代替滚动最大值,但是它非常慢。你能帮忙吗?在

仅供参考。我现在有一个丑陋而漫长的循环,不管它有多丑,在我的数据帧上似乎相当快(50000 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()

Tags: truedfnp整数nanwheremethodpd
2条回答

我将创建一个索引和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解决方案。尤其是当你的数据来自数据库时。离开熊猫进行数据分析。当然,如果你不是在数据库中存储大数据,那就完全是另一个问题了!在

Python为SQLite提供了一个内置库,该库是流行的免费、开放源代码的文件级数据库。此外,还可以安装用于MySQL、sqlserver、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)

输出(这里唯一的挑战是第一个分组,前面没有a==1)

^{pr2}$

相关问题 更多 >

    热门问题