【问题标题】:Pandas rolling weighted average熊猫滚动加权平均
【发布时间】:2018-04-26 09:49:45
【问题描述】:

我想将加权滚动平均值应用于大型时间序列,设置为 pandas 数据框,其中每天的权重都不同。这是数据框的子集

DF:

Date        v_std  vertical                  
2010-10-01  1.909   545.231
2010-10-02  1.890   538.610
2010-10-03  1.887   542.759
2010-10-04  1.942   545.221
2010-10-05  1.847   536.832
2010-10-06  1.884   538.858
2010-10-07  1.864   538.017
2010-10-08  1.833   540.737
2010-10-09  1.847   537.906
2010-10-10  1.881   538.210
2010-10-11  1.868   544.238
2010-10-12  1.856   534.878

我想使用 v_std 作为权重对垂直列进行滚动平均。我一直在使用加权平均函数:

def wavg(group, avg_name, weight_name):
    d = group[avg_name]
    w = group[weight_name]
    try:
        return (d * w).sum() / w.sum()
    except ZeroDivisionError:
        return d.mean()

但我不知道如何为滚动加权平均值实现这一点。我认为它类似于

df.rolling(window = 7).apply(wavg, "vertical", "v_std")

或使用rolling_apply?还是我必须一起编写一个新函数? 谢谢!

【问题讨论】:

标签: python pandas weighted-average


【解决方案1】:

这是我使用 pandas _Rolling_and_Expanding 滚动加权平均的解决方案:

首先,我为乘法添加了新列:

df['mul'] = df['value'] * df['weight']

然后编写你要应用的函数:

from pandas.core.window.rolling import _Rolling_and_Expanding
def weighted_average(x):
    d = []
    d.append(x['mul'].sum()/x['weight'].sum())
    return pd.Series(d, index=['wavg'])

_Rolling_and_Expanding.weighted_average = weighted_average

通过以下行应用函数:

result = mean_per_group.rolling(window=7).weighted_average()

那么你就可以通过以下方式获得你想要的系列:

result['wavg']

【讨论】:

  • 我收到cannot import name '_Rolling_and_Expanding' from 'pandas.core.window'
【解决方案2】:

下面的代码应该可以(请原谅我的长命名约定)。这很简单(只是利用 Pandas 的 rolling.apply 的新版本,它添加了 raw=False 以允许传递比一维数组更多的信息):

def get_weighted_average(dataframe,window,columnname_data,columnname_weights):
    processed_dataframe=dataframe.loc[:,(columnname_data,columnname_weights)].set_index(columnname_weights)   
    def get_mean_withweights(processed_dataframe_windowed):
        return np.average(a=processed_dataframe_windowed,weights=processed_dataframe_windowed.index)
    return processed_dataframe.rolling(window=window).apply(func=get_mean_withweights,raw=False)

【讨论】:

    【解决方案3】:

    这就是我实现加权平均的方式。如果这种事情有 pairwise_apply 就好了。

    from pandas.core.window import _flex_binary_moment, _Rolling_and_Expanding
    
    def weighted_mean(self, weights, **kwargs):
        weights = self._shallow_copy(weights)
        window = self._get_window(weights)
    
        def _get_weighted_mean(X, Y):
            X = X.astype('float64')
            Y = Y.astype('float64')
            sum_f = lambda x: x.rolling(window, self.min_periods, center=self.center).sum(**kwargs)
            return sum_f(X * Y) / sum_f(Y)
    
        return _flex_binary_moment(self._selected_obj, weights._selected_obj,
                                   _get_weighted_mean, pairwise=True)
    
    _Rolling_and_Expanding.weighted_mean = weighted_mean
    
    df['mean'] = df['vertical'].rolling(window = 7).weighted_mean(df['v_std'])
    

    【讨论】:

    • 与 pandas 0.25.3 配合得很好。但是,我添加以在传递到 1.0.3 时将导入更改为 from pandas.core.window.rolling import _flex_binary_moment, _Rolling_and_Expanding
    • 发生了更多重构,从 1.1 开始,您必须从 pandas.core.window.rolling import _Rolling_and_Expanding from pandas.core.window.common import _flex_binary_moment 导入`
    【解决方案4】:

    我相信你可能正在寻找rolling() 的win_type 参数。您可以指定不同类型的窗口,例如'triang'(三角形)...

    你可以看看https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rolling.html的参数

    【讨论】:

      猜你喜欢
      • 2019-02-13
      • 2022-08-16
      • 1970-01-01
      • 2015-01-12
      • 2019-07-27
      • 1970-01-01
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      相关资源
      最近更新 更多