简体   繁体   English

Python / Pandas用于解决分组平均值,中位数,众数和标准差

[英]Python/Pandas for solving grouped mean, median, mode and standard deviation

I have the following data: 我有以下数据:

[4.1, 4.1, 4.1, 4.2, 4.3, 4.3, 4.4, 4.5, 4.6, 4.6, 4.8, 4.9, 5.1, 5.1, 5.2, 5.2, 5.3, 5.3, 5.3, 5.4, 5.4, 5.5, 5.6, 5.6, 5.6, 5.7, 5.8, 5.9, 6.2, 6.2, 6.2, 6.3, 6.4, 6.4, 6.5, 6.6, 6.7, 6.7, 6.8, 6.8]

I need to build its count/frequency table like this based on the data above: 我需要根据上面的数据构建这样的计数/频率表:

4.1 - 4.5: 8
4.6 - 5.0: 4
5.1 - 5.5: 10
5.6 - 6.0: 6
6.1 - 6.5: 7
6.6 - 7.0: 5

The closest I can get is the following result: 我得到的最接近的结果是:

            counts  freqs
 categories               
[4.1, 4.6)       8  0.200
[4.6, 5.1)       4  0.100
[5.1, 5.6)      10  0.250
[5.6, 6.1)       6  0.150
[6.1, 6.6)       7  0.175
[6.6, 7.1)       5  0.125

Through this code: 通过此代码:

sr = [4.1, 4.1, 4.1, 4.2, 4.3, 4.3, 4.4, 4.5, 4.6, 4.6, 4.8, 4.9, 5.1, 5.1, 5.2, 5.2, 5.3, 5.3, 5.3, 5.4, 5.4, 5.5, 5.6, 5.6, 5.6, 5.7, 5.8, 5.9, 6.2, 6.2, 6.2, 6.3, 6.4, 6.4, 6.5, 6.6, 6.7, 6.7, 6.8, 6.8]
ncut = pd.cut(sr, [4.1, 4.6, 5.1, 5.6, 6.1, 6.6, 7.1],right=False)

srpd = pd.DataFrame(ncut.describe())

I need to create a new column, which is the median of the "categories" value (eg for "[4.1, 4.6)", this contains the count / frequency of data from 4.1 to 4.5 (not including 4.6)), So I need to get (4.1 + 4.5) / 2, which is equal to 4.3. 我需要创建一个新列,它是“类别”值的中值(例如,对于“ [4.1,4.6)”,它包含从4.1到4.5(不包括4.6)的数据计数/频率),所以我需要获得(4.1 + 4.5)/ 2,等于4.3。

Here are my questions: 这是我的问题:

1) How do I access the values under the "categories" index to use it for computation like above? 1)如何访问“类别”索引下的值以将其用于上述计算?

2) Is there a way to reflect the range in this way: 4.1 - 4.5, 4.6 to 5.0, etc..? 2)有没有办法以这种方式反映范围:4.1-4.5、4.6到5.0等?

3) Is there an easier way to compute for mean, median, mode, etc for grouped data like these? 3)是否有更简便的方法来计算像这样的分组数据的均值,中位数,众数等? or do I have to create my own functions for these in Python? 还是必须在Python中为这些函数创建自己的函数?

Thanks 谢谢

What about the following for your bins and labels issue: 对于您的垃圾箱和标签问题,以下内容如何处理:

bins = [4.1, 4.6, 5.1, 5.6, 6.1, 6.6, 7.1]
labels = ['{}-{}'.format(x, y-.1) for x,  y in zip(bins[:], bins[1:])]

Then instead of your values as a list, make them a Series 然后,而不是你的价值观作为一个列表,使他们成为一个Series

sr = pd.Series([4.1, 4.1, 4.1, 4.2, 4.3, 4.3, 4.4, 4.5, 4.6, 4.6, 4.8, 4.9, 5.1,
                5.1, 5.2, 5.2, 5.3, 5.3, 5.3, 5.4, 5.4, 5.5, 5.6, 5.6, 5.6, 5.7,
                5.8, 5.9, 6.2, 6.2, 6.2, 6.3, 6.4, 6.4, 6.5, 6.6, 6.7, 6.7, 6.8, 6.8])
ncut = pd.cut(sr, bins=bins, labels=labels, right=False)

Define a lambda function to calculate the frequency 定义一个lambda函数来计算频率

freq = lambda x: len(x) / x.sum()
freq.__name__ = 'freq'

Finally, use concat , groupby and agg to get your summary statistics per bin 最后,使用concatgroupbyagg获取每个bin的摘要统计信息

pd.concat([ncut, sr], axis=1).groupby(0).agg(['size', 'std', 'mean', freq])

Let's try: 我们试试吧:

l = [4.1, 4.1, 4.1, 4.2, 4.3, 4.3, 4.4, 4.5, 4.6, 4.6, 4.8, 4.9, 
     5.1, 5.1, 5.2, 5.2, 5.3, 5.3, 5.3, 5.4, 5.4, 5.5, 5.6, 5.6, 
     5.6, 5.7, 5.8, 5.9, 6.2, 6.2, 6.2, 6.3, 6.4, 6.4, 6.5, 6.6, 
     6.7, 6.7, 6.8, 6.8]

s = pd.Series(l)

bins = [4.1, 4.6, 5.1, 5.6, 6.1, 6.6, 7.1]
#Python 3.6+ f-string
labels = [f'{i}-{j-.1}' for i,j in zip(bins,bins[1:])]

(pd.concat([pd.cut(s, bins=bins, labels=labels, right=False),s],axis=1)
            .groupby(0)[1]
            .agg(['mean','median', pd.Series.mode, 'std'])
            .rename_axis('categories')
            .reset_index())

Output: 输出:

  categories      mean  median        mode       std
0    4.1-4.5  4.250000    4.25         4.1  0.151186
1    4.6-5.0  4.725000    4.70         4.6  0.150000
2    5.1-5.5  5.280000    5.30         5.3  0.131656
3    5.6-6.0  5.700000    5.65         5.6  0.126491
4    6.1-6.5  6.314286    6.30         6.2  0.121499
5    6.6-7.0  6.720000    6.70  [6.7, 6.8]  0.083666

I kind of figured out a noob way to do this: 我有点想办法做到这一点:

def buildFreqTable(data, width, numclass, pw):
data.sort()
minrange = []
maxrange = []
x_med = []
count = []

# Since data is already sorted, take the lowest value to jumpstart the creation of ranges
f_data = data[0]

for i in range(0,numclass):
    # minrange holds the minimum value for that row
    minrange.append(f_data)
    # maxrange holds the maximum value for that row
    maxrange.append(f_data + (width - pw)) 
    # Compute for range's median
    minmax_median = (minrange[i] + maxrange[i]) / 2
    x_med.append(minmax_median)
    # initialize count per numclass to 0, this will be incremented later
    count.append(0)

    f_data = f_data + width

# Tally the frequencies
for x in data:
    for i in range(0,6):
        if (x>=minrange[i] and x<=maxrange[i]):
            count[i] = count[i] + 1

# Now, create the pandas dataframe for easier manipulation
freqtable = pd.DataFrame()
freqtable['minrange'] = minrange
freqtable['maxrange'] = maxrange
freqtable['x'] = x_med
freqtable['count'] = count

buildFreqTable(sr, 0.5, 6, 0.1)

It gives off the following: 它散发出以下内容:

   minrange  maxrange    x  count
0       4.1       4.5  4.3      8
1       4.6       5.0  4.8      4
2       5.1       5.5  5.3     10
3       5.6       6.0  5.8      6
4       6.1       6.5  6.3      7
5       6.6       7.0  6.8      5

Though I am still curious if there is an easier way to do this, or if anyone could refactor my code to be more "pro-like" Thanks 尽管我仍然好奇是否有更简单的方法来执行此操作,或者是否有人可以将我的代码重构为更“亲”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM