使用Pandas计算整个数据集范围的分组数据的平均值

时间:2017-04-10 21:42:01

标签: python-2.7 pandas group-by mean

我有一个日常温度的数据集,我想用20年计算。数据如下所示:

1974  1  1  5.3  4.6  7.3  3.4  
1974  1  2  3.3  7.2  4.5  6.5  
...
2005  12  364  4.2  5.2  3.3  4.6
2005  12  365  3.1  5.5  2.6  6.8

文件中没有标题,但第一列包含年份,第二列包含月份,第三列包含一年中的日期。其余列是温度数据。

我想计算20年内每天的平均温度。我认为最好的方法是按天分组数据并计算特定年份范围内每天的平均值。这是我的代码:

import pandas as pd

hist_fn = 'tmean_daily_1974_2005.txt'
twenty_year_fn = '20_yr_mean_1974_1993.txt'

start = 1974
end = 1993

hist_mean = pd.read_csv(hist_fn, sep='\s+', header=None)

# Limit dataframe to only the 20 years for which I want the mean calculated
interval_mean = hist_mean[(hist_mean[0]>=start) & (hist_mean[0]<=end)]

# Rename the first column to reflect what mean this file is displaying
interval_mean.iloc[:, 0] = ("%s-%s" % (start, end))

# Generate mean for each day spread across all the years in the dataframe
interval_mean.iloc[:, 3:] = interval_mean.groupby(2, as_index=False).mean().iloc[:, 2:]

# Write multiyear mean to txt
interval_mean.to_csv(twenty_year_fn, sep='\t', header=False, index=False)

数据集的使用时间超过20年,我使用的方法在前20年的时间间隔内工作,但是对于我输入的任何其他年份,我给出了一个(大部分)空文本文件。

因此,当我使用这些输入时,它可以工作:

start = 1974
end = 1993

并生成一个如下所示的文件:

1974-1993  1  1  4.33  5.25  6.84  3.67  
1974-1993  1  2  7.23  6.22  5.65  6.23  
...
1974-1993  12  364  5.12  4.34  5.21  2.16
1974-1993  12  365  4.81  5.95  3.56  6.78

但是当我将输入更改为:

start = 1975
end = 1994

它生成一个没有温度的.txt文件:

1975-1994  1  1    
1975-1994  1  2    
...
1975-1994  12  364  
1975-1994  12  365  

我不明白为什么这种方法适用于前20年的间隔,但没有后续的间隔。这与数据的组织方式或切片方式有关吗?

1 个答案:

答案 0 :(得分:0)

现在,当这个问题解决时,我们可以谈谈您提出的问题:

奇怪的行为是由于 pandas匹配赋值时的索引切片保留了原始索引。这意味着在设置时

interval_mean.iloc[:, 3:] = interval_mean.groupby(2, as_index=False).mean().iloc[:, 2:]

请注意interval_mean.groupby(2, as_index=False).mean()有索引0, ... , 30(因为as_index=False使groupby操作创建新索引。否则,它将是天数。)另一个,interval_mean 1}}具有来自hist_mean的原始索引,这意味着第一次(前20年)它具有索引0, ..., ~20*365,第二次具有从arround 20*365开始并且向上计数的索引

起初这有点令人困惑,但是大熊猫提供了很好的documentation,人们很快发现它为何如此有用。 我将用一个例子来解释会发生什么:

假设我们有以下DataFrame

df = pd.DataFrame(np.reshape(np.random.randint(5, size=30), [-1,3]))
df

   0  1  2
0  1  1  2
1  2  1  1
2  0  1  2
3  0  2  0
4  2  1  0
5  0  1  2
6  2  2  1
7  1  0  2
8  0  1  0
9  1  2  0

请注意,列名称为0,1,2,行名称(索引)为0, ..., 9

当我们预先形成groupby时,我们获得了

df.groupby(0, as_index=False).mean()

   0         1         2
0  0  1.250000  1.000000
1  1  1.000000  1.333333
2  2  1.333333  0.666667

(索引等于仅因为02之间的绘制数字而分组的列)。现在,何时将对df.loc进行分配,如果存在此类单元格,它将替换受让人中相应单元格的每个单元格。否则,它将离开NA

df.loc[:,:] = df.groupby(0, as_index=False).mean()
df

     0         1         2
0  0.0  1.250000  1.000000
1  1.0  1.000000  1.333333
2  2.0  1.333333  0.666667
3 NaN  NaN       NaN
4 NaN  NaN       NaN
5 NaN  NaN       NaN
6 NaN  NaN       NaN
7 NaN  NaN       NaN
8 NaN  NaN       NaN
9 NaN  NaN       NaN

当您将NA写入csv时,它会将单元格留空。

最后一个难题是interval_mean如何保留原始索引,但这是因为切片保留了原始索引:

df[df[1] > 1]

   0  1  2
3  0  2  0
6  2  2  1
9  1  2  0