在Python DataFrame中检索平均值的平均值

4

我有一个大的pandas数据框df

year          count
1983          5
1983          4
1983          7
...
2009          8
2009          11
2009          30

我希望每年随机抽取10个数据点,这可以通过以下方法实现:

new_df = pd.DataFrame(columns=['year', 'count'])
ref = df.year.unique()

for i in range(len(ref)):
  appended_df = df[df['year'] == ref[i]].sample(n=10)
  new_df = pd.concat([new_df,appended_df])

然后,我随机给count赋予一个符号(这样随机情况下count可能是正数或负数),并将其重命名为value,可以通过以下方式完成:

vlist = []

for i in range(len(new_df)):
  if randint(0,1) == 0:
    vlist.append(new_df.count.iloc[i])
  else:
    vlist.append(new_df.count.iloc[i] * -1)

new_data['value'] = vlist

对于每个 year,获取其平均值和标准差非常简单:

xdf = new_data.groupby("year").agg([np.mean, np.std]).reset_index()

但是我似乎找不到一种尝试每年进行100次取样,并存储均值值并获取每年这100个均值的平均值和标准偏差的最佳方法。我考虑过使用for循环,但运行时间太长。

基本上,输出应该采用以下形式(这里的value是任意的):

year      mean_of_100_means  total_sd
1983      4.22               0.43
1984      -6.39              1.25
1985      2.01               0.04
...
2007      11.92              3.38
2008      -5.27              1.67
2009      1.85               0.99

欢迎提供任何想法。


你能发布一个样本DataFrame,以便我们可以复制并运行吗? - Shubham Periwal
为什么要给count分配一个随机符号? - Derek O
2个回答

3

我认为你可以使用pandas的 groupbysample 函数来从DataFrame中每一年中随机抽取10个样本。如果将此放入循环中,则可以对其进行100次抽样并合并结果。

听起来你只需要计算100个均值的标准偏差(不需要10个观测样本的标准偏差),因此你可以在groupby和sample中仅计算均值,然后在创建最终DataFrame的total_sd列时,从这100个均值中计算标准偏差。

import numpy as np
import pandas as pd

np.random.seed(42)

## create a random DataFrame with 100 entries for the years 1980-1999, length 2000
df = pd.DataFrame({
    'year':[year for year in list(range(1980, 2000)) for _ in range(100)],
    'count':np.random.randint(1,100,size=2000)
})

list_of_means = []

## sample 10 observations from each year, and repeat this process 100 times, storing the mean for each year in a list
for _ in range(100):
    df_sample = df.groupby("year").sample(10).groupby("year").mean()
    list_of_means.append(df_sample['count'].tolist())
array_of_means = [np.array(x) for x in list_of_means]

result = pd.DataFrame({
    'year': df.year.unique(),
    'mean_of_100_means': [np.mean(k) for k in zip(*array_of_means)],
    'total_sd': [np.std(k) for k in zip(*array_of_means)]
})

这将导致:
>>> result
    year  mean_of_100_means  total_sd
0   1980             50.316  8.656948
1   1981             48.274  8.647643
2   1982             47.958  8.598455
3   1983             49.357  7.854620
4   1984             48.977  8.523484
5   1985             49.847  7.114485
6   1986             47.338  8.220143
7   1987             48.106  9.413085
8   1988             53.487  9.237561
9   1989             47.376  9.173845
10  1990             46.141  9.061634
11  1991             46.851  7.647189
12  1992             49.389  7.743318
13  1993             52.207  9.333309
14  1994             47.271  8.177815
15  1995             52.555  8.377355
16  1996             47.606  8.668769
17  1997             52.584  8.200558
18  1998             51.993  8.695232
19  1999             49.054  8.178929

3

请尝试:

def fn(x):
    _100_means = [x.sample(10).mean() for i in range(100)]
    return {
        "mean_of_100_means": np.mean(_100_means),
        "total_sd": np.std(_100_means),
    }


print(df.groupby("year")["count"].apply(fn).unstack().reset_index())

编辑:更改均值计算方法。

输出:

    year  mean_of_100_means   total_sd
0   1983             48.986   8.330787
1   1984             48.479  10.384896
2   1985             48.957   7.854900
3   1986             50.821  10.303847
4   1987             50.198   9.835832
5   1988             47.497   8.678749
6   1989             46.763   9.197387
7   1990             49.696   8.837589
8   1991             46.979   8.141969
9   1992             48.555   8.603597
10  1993             50.220   8.263946
11  1994             48.735   9.954741
12  1995             49.759   8.532844
13  1996             49.832   8.998654
14  1997             50.306   9.038316
15  1998             49.513   9.024341
16  1999             50.532   9.883166
17  2000             49.195   9.177008
18  2001             50.731   8.309244
19  2002             48.792   9.680028
20  2003             50.251   9.384759
21  2004             50.522   9.269677
22  2005             48.090   8.964458
23  2006             49.529   8.250701
24  2007             47.192   8.682196
25  2008             50.124   9.337356
26  2009             47.988   8.053438

数据框已创建:

data = []
for y in range(1983, 2010):
    for i in np.random.randint(0, 100, size=1000):
        data.append({"year": y, "count": i})
df = pd.DataFrame(data)

你的答案看起来比我的更干净,但我想知道为什么 total_sd 列的值始终比我的高?据我所知,我们的方法是相同的,唯一的区别在于我们选择每年的观测次数不同。 - Derek O
1
@DerekO 我重新阅读了原帖的问题,我计算平均值时出错了——原帖的问题是要计算100个平均值,然后再计算这100个平均值的平均值。我改变了我的函数,现在看起来相似了。 - Andrej Kesely
1
啊,现在明白了。希望我们两个的回答都能帮助到楼主! - Derek O

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接