【问题标题】:Getting weighted average and standard deviation on several columns in Pandas在 Pandas 中的几列上获取加权平均值和标准差
【发布时间】:2018-06-26 17:18:09
【问题描述】:

我正在尝试在我的 pandas 数据帧的加权平均值之上做加权标准差。我有一个pandas 数据框,例如:

import numpy as np
import pandas as pd
df = pd.DataFrame({"Date": pd.date_range(start='2018-01-01', end='2018-01-03 18:00:00', freq='6H'),
               "Weight": np.random.uniform(3, 5, 12),
               "V1": np.random.uniform(10, 15, 12),
               "V2": np.random.uniform(10, 15, 12),
               "V3": np.random.uniform(10, 15, 12)})

目前,为了获得加权平均值,受this post 的启发,我正在执行以下操作:

def weighted_average_std(grp):
    return grp._get_numeric_data().multiply(grp['Weight'], axis=0).sum()/grp['Weight'].sum()
df.index = df["Date"]
df_agg = df.groupby(pd.Grouper(freq='1D')).apply(weighted_average_std).reset_index()
df_agg

我从哪里得到以下信息:

    Date    V1  V2  V3  Weight
0   2018-01-01  11.421749   13.090178   11.639424   3.630196
1   2018-01-02  12.142917   11.605284   12.187473   4.056303
2   2018-01-03  12.034015   13.159132   11.658969   4.318753

我想修改weighted_average_std,使其返回除weighted average 之外的每一列的标准差。这个想法是以矢量化的方式使用每个组的加权平均值。 Weighted Standard Deviation 的新列名称可以是 V1_WSDV2_WSDV3_WSD

PS1:This post 通过加权标准差理论。

PS2:df_agg 中的列 Weight 没有意义。

【问题讨论】:

    标签: python pandas grouping aggregate weighted-average


    【解决方案1】:

    你可以使用EOL's NumPy-based code 计算加权平均值和标准差。要在 Pandas groupby/apply 操作中使用它,请让 weighted_average_std 返回一个 DataFrame:

    import numpy as np
    import pandas as pd
    
    
    def weighted_average_std(grp):
        """
        Based on http://stackoverflow.com/a/2415343/190597 (EOL)
        """
        tmp = grp.select_dtypes(include=[np.number])
        weights = tmp['Weight']
        values = tmp.drop('Weight', axis=1)
        average = np.ma.average(values, weights=weights, axis=0)
        variance = np.dot(weights, (values - average) ** 2) / weights.sum()
        std = np.sqrt(variance)
        return pd.DataFrame({'mean':average, 'std':std}, index=values.columns)
    
    np.random.seed(0)
    df = pd.DataFrame({
        "Date": pd.date_range(start='2018-01-01', end='2018-01-03 18:00:00', freq='6H'),
        "Weight": np.random.uniform(3, 5, 12),
        "V1": np.random.uniform(10, 15, 12),
        "V2": np.random.uniform(10, 15, 12),
        "V3": np.random.uniform(10, 15, 12)})
    
    df.index = df["Date"]
    df_agg = df.groupby(pd.Grouper(freq='1D')).apply(weighted_average_std).unstack(-1)
    print(df_agg)
    

    产量

                     mean                             std                    
                       V1         V2         V3        V1        V2        V3
    Date                                                                     
    2018-01-01  12.105253  12.314079  13.566136  1.803014  1.725761  0.679279
    2018-01-02  13.223172  12.534893  11.860456  1.709583  0.950338  1.153895
    2018-01-03  13.782625  12.013557  12.105231  0.969099  1.189149  1.249064
    

    【讨论】:

    • 这很好用。你能解释一下unstack(-1) 的作用吗?
    • 了解unstack 的最佳方式是使用示例(例如链接页面上显示的示例,或者此处显示的示例)。考虑它的一种方法是专注于它如何影响行和列索引——unstack 将行索引级别移动到新的列索引级别。根据需要重新调整数据。 -1 告诉 unstack 移动最后一行索引级别——V1V2V3 值,而不是 Dates。
    • 这是有道理的。我正在使用以下行来使列名变平。如果有更优雅的方法,请告诉我们。它将产生V1_stdV1_mean 之类的名称,df_agg.columns = [col[1] + "_" + col[0] if (col[0] != "" and col[1] != "") else col[1] + col[0] for col in df_agg.columns.values]
    • 这行得通,或者你可以使用类似df_agg.columns = df_agg.swaplevel(axis=1).columns.map('_'.join) 的东西。请注意,保留MultiIndex 可能是有利的,特别是如果您希望仅选择均值,或仅选择标准,或仅选择与V1 关联的数据,例如。
    • np.average 更改为np.ma.average。链接的文档页面指向答案(搜索ZeroDivisionError)。通过此更改,df_agg 将包含带有NaNs 的行。如果您想删除这些行,请使用df_agg = df_agg.dropna()
    猜你喜欢
    • 2012-04-20
    • 2013-05-22
    • 1970-01-01
    • 2020-12-26
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    相关资源
    最近更新 更多