我有一个文本文件,里面有六年来四月和五月的温度数据。我想计算每年每个月的平均值。我正在使用 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.groupby
:https://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.