如何计算特定列按月和按年计算的平均值?

如何计算特定列按月和按年计算的平均值?

我有一个文本文件,里面有六年来四月和五月的温度数据。我想计算每年每个月的平均值。我正在使用 awk 命令,但它计算的是总体温度平均值。我不知道如何使用 awk 命令来解决这个问题。

awk '{sum+=$6; n++} END {print sum/n;}' vk4.txt

我正在展示的示例文件,

STATION_ID,LATITUDE,LONGITUDE,TIME(GMT),DATE(GMT),AIR_TEMP(°C)
IMDE1611_14164B(PITAMPURA)  28.7    77.15   1   04/05/2012  31.4
IMDE1611_14164B(PITAMPURA)  28.7    77.15   2   04/05/2012  31.9
IMDE1611_14164B(PITAMPURA)  28.7    77.15   3   04/05/2012  32.6
IMDE1611_14164B(PITAMPURA)  28.7    77.15   2   05/01/2012  32.1
IMDE1611_14164B(PITAMPURA)  28.7    77.15   3   05/01/2012  32.3
IMDE1611_14164B(PITAMPURA)  28.7    77.15   4   05/01/2012  33
IMDE1611_14164B(PITAMPURA)  28.7    77.15   5   04/01/2013  33.9
IMDE1611_14164B(PITAMPURA)  28.7    77.15   6   04/01/2013  34.2
IMDE1611_14164B(PITAMPURA)  28.7    77.15   7   04/01/2013  34.8

答案1

另一个非常灵活的 Python 解决方案基于itertools.groupbyhttps://github.com/davidfoerster/group-aggregate

安装

wget https://github.com/davidfoerster/group-aggregate/raw/master/group-aggregate.py
chmod +x group-aggregate.py

用法

./group-aggregate.py [--skip N] [options...] groups aggregators...
  • groups– 用于分组记录的字段索引或列范围列表(从零开始,以逗号分隔)。

  • aggregators– 字段索引(从零开始)或列范围、聚合函数的名称以及可选的格式字符串,全部以冒号分隔。

  • --skip N- 跳过输入开头的 N 行(例如标题行)。

查看输出python3 -O group-aggregate.py --help以了解更多。

例子

示例 1

分组和聚合程序无法处理部分字段;让我们用其他工具重新格式化您的数据集来解决它:

awk '{ gsub(/\//, OFS, $5); print; }'  | ...

现在,分组字段年份的索引为 6,聚合字段温度的索引为 7,您想对其取平均值:

... | ./group-aggregate.py --skip 1 6 7:favg < data.csv

你也可以格式温度平均值,在此示例中精确显示一位小数:

... | ./group-aggregate.py --skip 1 6 7:favg:.1f

示例 2

您还可以指定与您的数据格式相匹配的列范围,而不是字段分隔符:

./group-aggregate.py --skip 1 54-58 60-:favg:.1f < data.csv

现在您甚至不需要像示例 1 那样预先格式化数据。

输出

两个示例命令的输出相同:

2012    32.2
2013    34.3

答案2

你可以用一个小 Python 脚本来实现这一点:

#!/usr/bin/env python3

import sys
if len(sys.argv) != 2:
    print("You must provide exactly one filename to read as argument.")
    exit(-1)

file = open(sys.argv[1])
file.readline()  # to strip headline

dict = {}
for line in file:
    datestr, tempstr = line.split()[4:]
    year, temp = int(datestr.split("/")[-1]), float(tempstr)
    dict.setdefault(year, []).append(temp)

for year in dict:
    print("{0}:\t{1:.2f}".format(year, sum(dict[year]) / len(dict[year])))

它在逐行执行脚本时读取作为参数指定的文件,并创建一个将年份映射到温度值列表的字典。处理完整个文件后,它将计算并打印每年的平均温度。

以下是使用您提供的数据文件运行的示例vk4.txt。我将上述脚本保存为avgtemp.py当前目录,并使用以下命令使其可执行chmod +x avgtemp.py

$ ./avgtemp.py vk4.txt
2012:   32.22
2013:   34.30

如果需要,只需编辑"{0}:\t{1:.2f}"脚本最后一行的格式字符串,即可轻松修改确切的输出格式。您可以在此处输入任何模式,只要它包含{0}以替换年份和{1:.2f}或类似 以替换平均温度(显示两位小数)。 是\t一个制表符。

答案3

基本思想是从日期字段创建年月键,然后使用关联数组根据该键对条目进行求和和计数,例如

awk '
  NR>1 {
    split($5,d,"/"); s[d[3]"/"d[1]]+=$6; c[d[3]"/"d[1]]++;
  } 
  END {
    for (i in s) print i, s[i]/c[i]
  }' vk4.txt

使用您的数据进行测试:

$ mawk '
  NR>1 {
    split($5,d,"/"); s[d[3]"/"d[1]]+=$6; c[d[3]"/"d[1]]++;
  } 
  END {
    for (i in s) print i, s[i]/c[i];
  }' vk4.txt
2012/04 31.9667
2012/05 32.4667
2013/04 34.3

如果您有 GNU awk ( gawk) v4+,您可以添加显式排序。

答案4

这可能更适合 Stack Overflow;但是,这里有一个使用 Python 的解决方案,您应该temperature_data.txt在第一行用您的文件替换它。

f=open("temperature_data.txt","r") ### REPLACE temperature_data.txt WITH THE FILE CONTAINING YOUR DATA
flines=f.readlines() #read the file in question
f.close()

flines_split=[line.split() for line in flines] #split each line up
data_split=[line for line in flines_split if len(line)>=5 and line[4].count("/")==2] #get only lines with the date in
gathered_data={}
for line in data_split: #this block sanitises the data
    month=int(line[4][:2]) ### NOTE THAT THIS ASSUMES YOU ARE USING AMERICAN DATE FORMAT
    ### IF YOU ARE NOT, REPLACE "month=int(line[4][:2])" WITH "month=int(line[4][3:5])"
    year=int(line[4][6:])
    if (month,year) in gathered_data:
        gathered_data[(month,year)].append(float(line[5]))
    else:
        gathered_data[(month,year)]=[float(line[5])]

def mean(l): #function to calculate means
    return sum(l)/float(len(l))

means={k:mean(gathered_data[k]) for k in gathered_data} #calculate means

print("Month Year Temperature")
for k in sorted(list(means)): #print output
    print("{date[0]:^5} {date[1]} {temp:.4}".format(date=k,temp=means[k])) ### the 4 in {temp:.4} specifies precision and can be modified.

相关内容