【问题标题】:Python Dataframe Rolling median with group byPython数据框滚动中位数与分组依据
【发布时间】:2017-12-05 18:26:49
【问题描述】:

我有一个包含三列的数据框,即datecommodityvalues。我想添加另一列median_20,即df 中每个commodity 过去20 天的滚动中位数。另外,我想添加其他显示值 n 天前的列,例如,lag_1 列显示给定 commodity 前 1 天的值,lag_2 显示前 2 天的值,依此类推。我的df 非常大(>200 万行)。

dates = pd.date_range('2017-01-01', '2017-07-02')
df1 = pd.DataFrame({'date':dates, 'commodity':np.random.normal(size = len(dates)), 'market':'GOLD'})
df2 = pd.DataFrame({'date':dates, 'commodity':np.random.normal(size = len(dates)), 'market':'SILVER'})
df = pd.concat([df1, df2])
df = df.sort('date')

          date  commodity     value
0   2017-01-01       GOLD -1.239422
0   2017-01-01     SILVER -0.209840
1   2017-01-02     SILVER  0.146293
1   2017-01-02       GOLD  1.422454
2   2017-01-03       GOLD  0.453222
...

【问题讨论】:

    标签: python dataframe group-by median


    【解决方案1】:

    试试:

    import pandas as pd
    import numpy as np
    
    # create dataframe
    dates = pd.date_range('2017-01-01', '2017-07-02')
    df1 = pd.DataFrame({'date':dates, 'commodity':np.random.normal(size = len(dates)), 'market':'GOLD'})
    df2 = pd.DataFrame({'date':dates, 'commodity':np.random.normal(size = len(dates)), 'market':'SILVER'})
    df = pd.concat([df1, df2])
    df = df.sort_values(by='date').reset_index(drop=True)
    
    # create columns
    df['median_20_temp'] = df.groupby('market')['commodity'].rolling(20).median()
    df['median_20'] = df.groupby('market')['median_20_temp'].shift(1)
    df['lag_1'] = df.groupby('market')['commodity'].shift(1)
    df['lag_2'] = df.groupby('market')['commodity'].shift(2)
    df.drop(['median_20_temp'], axis=1, inplace=True)
    

    编辑:

    以下内容应适用于版本0.16.2

    import numpy as np
    import pandas as pd
    
    
    np.random.seed(123)
    dates = pd.date_range('2017-01-01', '2017-07-02')
    df1 = pd.DataFrame({'date':dates, 'commodity':np.random.normal(size = len(dates)), 'market':'GOLD'})
    df2 = pd.DataFrame({'date':dates, 'commodity':np.random.normal(size = len(dates)), 'market':'SILVER'})
    df = pd.concat([df1, df2])
    df = df.sort('date').reset_index(drop=True)
    
    # create columns
    df['median_20_temp'] = df.groupby('market')['commodity'].apply(lambda s: pd.rolling_median(s, 20))
    df['median_20'] = df.groupby('market')['median_20_temp'].shift(1)
    df['lag_1'] = df.groupby('market')['commodity'].shift(1)
    df['lag_2'] = df.groupby('market')['commodity'].shift(2)
    df.drop(['median_20_temp'], axis=1, inplace=True)
    

    我希望这会有所帮助。

    【讨论】:

    • 感谢您的回复@Abdou。我试过这个,但它抛出AttributeError: 'SeriesGroupBy' object has no attribute 'rolling'。在我的办公室里,我们使用版本“0.16.2”的 pandas,不幸的是,在我们的生产环境中升级它并不容易。这是执行第一条语句时的错误 -df['median_20'] = ...
    • 第二个和第三个语句抛出以下错误 - pandas/core/groupby.py, line 581, in wrapper raise ValueError ValueError
    • @Gerry 不幸的是,我无法调试我看不到的数据的代码。我正在处理您在此处提供的数据。请分享引发这些错误的数据。另外,请确保您使用的是最新版本的 pandas。
    • 上述数据框出现这些错误。正如您正确指出的那样,这些与我正在使用的熊猫版本有关。不幸的是,在我们的办公环境中升级 pandas 对我来说并不容易。
    • lag_1lag_2 语句工作正常。然而,对于median_20 声明,它并没有给出正确的结果。它没有失败,但如果您检查结果,这些结果不是 commodities 列中前 20 个值的中位数。
    【解决方案2】:

    我确信有一个更有效的方法,同时尝试这个解决方案:

    for commo in df.market.unique():
        df.loc[df.market==commo,'lag_1'] = df.loc[df.market==commo,'commodity'].shift(1)
        df.loc[df.market==commo,'median_20'] = pd.rolling_median(df.loc[df.market==commo,'commodity'],20)
    

    【讨论】:

    • 感谢@user7235865。 for 循环中的第一条语句工作正常。然而第二个语句 - df.loc[df.market==commo,'median_20'] = ... 抛出 AttributeError: 'Series' object has no attribute 'rolling'。我认为这个错误可能与旧版本的熊猫有关,但在我的办公室中,我们使用熊猫的“0.16.2”版本,不幸的是,在我们的生产环境中升级它并不容易。有没有办法解决这个问题?
    • @Gerry:用pd.rolling_median试试这个新版本
    • 这就是我最终使用的并且有效。谢谢。对于大型数据帧,for 循环非常慢。
    • 另外,df.loc[df.market==commo,'median_20']... 语句直到最后都不是中间值,但也包括当前行。解决此问题的一种方法是将shift(1) 也应用于median_20 列。
    猜你喜欢
    • 2020-10-12
    • 2020-04-28
    • 2019-10-08
    • 2019-08-05
    • 1970-01-01
    • 2019-01-22
    • 2021-11-04
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多