【问题标题】:How to get Mean and Standard deviation from a Frequency Distribution table in Python如何从 Python 中的频率分布表中获取均值和标准差
【发布时间】:2018-02-15 14:53:09
【问题描述】:

我有一个元组列表 [(val1, freq1), (val2, freq2) .... (valn, freqn)]。我需要获取上述数据的中心趋势(均值、中位数)和偏差测量值(方差、均值)。我还想为这些值绘制箱线图。

我看到 numpy 数组具有从值列表中获取平均值/中值和标准差(或方差)的直接方法。

numpy(或任何其他知名库)是否有直接的方法来操作这样的频率分布表?

另外,以编程方式将上述元组列表扩展为一个列表的最佳方法是什么? (例如,如果 freq dist 是 [(1,3) , (50,2)],则获取列表 [1,1,1,50,50] 以使用 np.mean([1,1,1, 50,50]))

我看到了一个自定义函数here,但如果可能的话我想使用一个标准的实现

【问题讨论】:

  • @ayhan 我已将您的解决方案归因于描述......并澄清了我在寻找什么。可以去掉重复的标签吗?

标签: python python-3.x numpy dataframe


【解决方案1】:

首先,我会像 @user8153 那样将那个凌乱的列表更改为两个 numpy 数组:

val, freq = np.array(list_tuples).T

然后你可以重构数组(使用np.repeat防止循环):

data = np.repeat(val, freq)

并在您的 data 数组上使用 numpy statistical functions


如果这会导致内存错误(或者您只是想尽可能多地挤出性能),您还可以使用一些专门构建的函数:

def mean_(val, freq):
    return np.average(val, weights = freq)

def median_(val, freq):
    ord = np.argsort(val)
    cdf = np.cumsum(freq[ord])
    return val[ord][np.searchsorted(cdf, cdf[-1] // 2)]

def mode_(val, freq): #in the strictest sense, assuming unique mode
    return val[np.argmax(freq)]

def var_(val, freq):
    avg = mean_(val, freq)
    dev = freq * (val - avg) ** 2
    return dev.sum() / (freq.sum() - 1)

def std_(val, freq):
    return np.sqrt(var_(val, freq))

【讨论】:

  • 函数“var_”中的“return dev.sum() / (freq.sum() - 1)”错误,“Float64Index”对象没有属性“sum”
  • @ppau2004 我敢肯定pandas 有自己的,更好地实现的版本。可能想问一个问题,如果你找不到它怎么办(我不是pandas 专家,但这里有很多)
  • 其实,@AditjaRajgor 下面有一个pandas 答案
【解决方案2】:
  • 将(值,频率)列表转换为值列表:

    freqdist =  [(1,3), (50,2)]
    sum(([val,]*freq for val, freq in freqdist), []) 
    

    给予

    [1, 1, 1, 50, 50]
    
  • 要计算平均值,您可以使用 np.average 来避免构建值列表,该参数采用 weights 参数:

    vals, freqs = np.array(freqdist).T
    np.average(vals, weights = freqs)
    

    如您所料,给出 20.6。不过,我认为这不适用于均值、方差或标准差。

【讨论】:

    【解决方案3】:
    import pandas as pd
    import math
    import numpy as np
    

    频率分布数据

        class   freq
    0   60-65   3
    1   65-70   150
    2   70-75   335
    3   75-80   135
    4   80-85   4
    

    为类创建中间点列

    df[['Upper','Lower']]=df['class'].str.split('-',expand=True)
    df['Xi']=(df['Upper'].astype(float)+df['Lower'].astype(float))/2
    df.drop(['Upper','Lower'],axis=1,inplace=True)
    

    因此

        class   freq  Xi
    0   60-65   3     62.5
    1   65-70   150   67.5
    2   70-75   335   72.5
    3   75-80   135   77.5
    4   80-85   4     82.5
    

    平均值

    mean = np.average(df['Xi'], weights=df['freq'])
    mean
    72.396331738437
    

    标准偏差

    std = np.sqrt(np.average((df['Xi']-mean)**2,weights=df['freq']))
    std
    3.5311919641103877
    

    【讨论】: