代码之家  ›  专栏  ›  技术社区  ›  Pythonista anonymous

如何平滑并绘制x与y的加权平均值,用x加权?

  •  0
  • Pythonista anonymous  · 技术社区  · 5 年前

    • 离散权重,并为每个权重间隔绘制 加权平均值

    有没有一个简单的方法来实现这一点?我找到了一个方法,但它似乎有点麻烦:

    • 我用pandas.cut()离散数据帧
    • 进行分组并计算加权平均值
    • 绘制每个箱子的平均值与加权平均值
    • 我也尝试过用样条曲线平滑曲线,但效果不太好

    我的输出如下所示: enter image description here

    我的代码,加上一些随机数据,是:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    from scipy.interpolate import make_interp_spline, BSpline
    
    n=int(1e3)
    df=pd.DataFrame()
    np.random.seed(10)
    df['w']=np.arange(0,n)
    df['v']=np.random.randn(n)
    df['ranges']=pd.cut(df.w, bins=50)
    df['one']=1.
    def func(x, df):
        # func() gets called within a lambda function; x is the row, df is the entire table
        b1= x['one'].sum()
        b2 = x['w'].mean()
        b3 = x['v'].mean()       
        b4=( x['w'] * x['v']).sum() / x['w'].sum() if x['w'].sum() >0 else np.nan
    
        cols=['# items','avg w','avg v','weighted avg v']
        return pd.Series( [b1, b2, b3, b4], index=cols )
    
    summary = df.groupby('ranges').apply(lambda x: func(x,df))
    
    sns.set(style='darkgrid')
    
    fig,ax=plt.subplots(2)
    sns.lineplot(summary['avg w'], summary['weighted avg v'], ax=ax[0])
    ax[0].set_title('line plot')
    
    xnew = np.linspace(summary['avg w'].min(), summary['avg w'].max(),100)
    spl = make_interp_spline(summary['avg w'], summary['weighted avg v'], k=5) #BSpline object
    power_smooth = spl(xnew)
    sns.lineplot(xnew, power_smooth, ax=ax[1])
    ax[1].set_title('not-so-interpolated plot')
    
    0 回复  |  直到 5 年前
        1
  •  1
  •   P.Tillmann Zhongxia Yan    5 年前

    你问题的第一部分很容易回答。

    我不知道你说的第二部分是什么意思。您想要(简化的)代码复制还是一种更适合您需要的新方法?

    无论如何,我必须看一下你的代码,才能理解加权值的含义。我认为人们通常会期望与这个词有所不同(只是作为一个警告)。

    以下是您的方法的简化版本:

    df['prod_v_w'] = df['v']*df['w']
    weighted_avg_v = df.groupby(pd.cut(df.w, bins=50))[['prod_v_w','w']].sum()\
                       .eval('prod_v_w/w')
    print(np.allclose(weighted_avg_v, summary['weighted avg v']))
    Out[18]: True
    
        2
  •  1
  •   TavoGLC    5 年前

    我认为你在插值中使用了很少的值,通过改变 xnew = np.linspace(summary['avg w'].min(), summary['avg w'].max(),100) xnew = np.linspace(summary['avg w'].min(), summary['avg w'].max(),500) 我得到以下信息:

    enter image description here

    并将样条曲线的阶数更改为 k=2 我得到以下信息:

    enter image description here

    我认为插值的一个很好的起点是 n/2 k=2 因为它呈现较少的数据变形。希望能有帮助。

        3
  •  0
  •   Danny    5 年前

    如果我理解正确的话,你是在试图重建一个滚动平均值。

    rolling 功能:

    dataframe.rolling(n).mean()

    哪里 n

    您可以在此处找到示例:

        4
  •  0
  •   erncyp    5 年前

    我认为这是你所寻求的解决办法。正如其他人所建议的,它使用滚动窗口。要使它正常工作,还需要多做一点工作。

    df["w*v"] = df["w"] * df["v"]
    
    def rolling_smooth(df,N):
        df_roll = df.rolling(N).agg({"w":["sum","mean"],"v":["mean"],"w*v":["sum"]})
        df_roll.columns = [' '.join(col).strip() for col in df_roll.columns.values]
        df_roll['weighted avg v'] = np.nan
        cond = df_roll['w sum'] > 0
        df_roll.loc[cond,'weighted avg v'] = df_roll.loc[cond,'w*v sum'] / df_roll.loc[cond,'w sum']
        return df_roll
    
    df_roll_100 = rolling_smooth(df,100)
    df_roll_200 = rolling_smooth(df,200)
    
    plt.plot(summary['avg w'], summary['weighted avg v'],label='original')
    plt.plot(df_roll_100["w mean"],df_roll_100["weighted avg v"],label='rolling N=100')
    plt.plot(df_roll_200["w mean"],df_roll_200["weighted avg v"],label='rolling N=200')
    plt.legend()
    

    enter image description here