awk 计算平均值,但仅针对某些列中的特定值

awk compute average, but only for specific values in certain columns

我有一个包含 6 列和 100 万行的 csv 文件。示例文件是这样的:

19;19;2021-06-01;0;France;10.3991
19;19;2021-06-01;0;Germany;0
19;19;2021-06-01;0;Others;8.08681
19;19;2021-06-01;0;Portugal;2486.39
19;19;2021-06-01;0;Spain;7.70791
19;19;2021-06-01;2;Switzerland;5.3688
19;19;2021-06-01;2;United Kingdom;0.00256085
19;19;2021-06-01;2;France;13.4166
19;19;2021-06-01;4;Germany;0

所有列都可以有不同的值(例如,第一列和第二列可以有“19”、“20”、“21”等值。第三列从 2021 年开始-06-01 至 2021-06-29。第四列可以有“2”、“4”、“6”……最多为“22”。第五列可以有不同的国籍)。

我需要根据“2021-06-02”、“2021-06-09”、“2021-06-16”和“2021-06”这几天的值计算第 6 列的平均值-16”,并将其分配给“2021-06-30”这一天。

但是某些列中的某些值并非所有天都存在。

换句话说,我需要检查这些不同日期的第 1、2、4、5 列的值是否相同,然后计算这四天的第 6 列的平均值。

例如:

19;19;2021-06-02;0;France;Value1
19;19;2021-06-09;0;France;Value2
19;19;2021-06-16;0;France;Value3
19;19;2021-06-23;0;France;Value4

然后,Averagevalue=(Value1+Value2+Value3+Value4)/4

有了这个,我可以将平均值指定为:

19;19;2021-06-30;0;France;Averagevalue

接下来,

19;19;2021-06-02;2;France;Value1
19;19;2021-06-09;2;France;Value2
19;19;2021-06-23;2;France;Value3

然后,Averagevalue=(Value1+Value2+Value3)/3

有了这个,我可以将平均值指定为:

19;19;2021-06-30;2;France;Averagevalue

并对第 1、2、4 和 5 列的所有可能值重复此过程。

我试过这个:

awk -F";" '{if(=="2021-06-02"||=="2021-06-09"||=="2021-06-16"||=="2021-06-23") seen[";"";"";"]+= count[";"";"";"]++} END { for (i in seen) print i, seen[i]/count[i] }' input.csv 

没有成功。有什么想法吗?

让我们更正您的示例,使用一致的 ; 作为分隔符。

给定一个这样的文件:

$ cat file
19;19;2021-06-01;0;France;10.3991
19;19;2021-06-01;0;Germany;0
19;19;2021-06-01;0;Others;8.08681
19;19;2021-06-01;0;Portugal;2486.39
19;19;2021-06-01;0;Spain;7.70791
19;19;2021-06-01;2;Switzerland;5.3688
19;19;2021-06-01;2;United Kingdom;0.00256085
19;19;2021-06-01;2;France;13.4166
19;19;2021-06-01;4;Germany;0
19;19;2021-06-02;0;France;1
19;19;2021-06-09;0;France;2
19;19;2021-06-16;0;France;3
19;19;2021-06-23;0;France;4
19;19;2021-06-24;0;France;5
19;19;2021-06-25;0;France;6
19;19;2021-06-26;0;France;7

由于您似乎有 ISO 8601 日期戳,您可以通过字符串比较过滤日期 范围

$ awk -F ";" '>="2021-06-02" && <="2021-06-23"' file
19;19;2021-06-02;0;France;1
19;19;2021-06-09;0;France;2
19;19;2021-06-16;0;France;3
19;19;2021-06-23;0;France;4

或者,如果您只想要这四个特定日期,您可以像这样创建一个感兴趣的日期数组:

awk -F ";" -v dates="2021-06-02;2021-06-09;2021-06-16;2021-06-23" '
BEGIN{split(dates,a,";"); for (e in a) datesa[a[e]]}
 in datesa' file
# same output

现在您可以计算运行过滤的平均值:

awk -F ";" '>="2021-06-02" && <="2021-06-23"{
    sum+=; cnt++; r=sprintf("%s,%s,2021-06-30,%s,%s,%s",,,,,sum/cnt)
}
END{print r}' file

打印:

19,19,2021-06-30,0,France,2.5

注意:这不会根据 国家/地区进行过滤,也不会执行任何操作,只会为示例中的其他字段取最后一个值,因为未指定。

我终于通过两遍 awk 解决了我的问题:

awk -F";" '{if(=="2021-06-02"||=="2021-06-09"||=="2021-06-16"||=="2021-06-23") print ";"";"";"";"}' june2021-no30.csv > 4dnd

awk -F";" '{s[";"";"";"]+= c[";"";"";"]++ } END { for (i in s) print i";"s[i]/c[i]";20210630" }' 4dnd > 4dave

然后,通过排序和一些重新格式化,我得到了我需要的文件

awk 中的过滤应该在 {}

之外完成

可以使用以下代码过滤所需的日期:

~"2021-06-" && substring(,length()-1)%7==2

mod-operator(%)计算整数除法后的余数,所以本例returns2021年6月的所有星期三(包括第30个)

因此,您的第一行可能如下所示:

awk -F";" '~/2021-06-[012]/ && substring(,length()-1)%7==2{ print ";"";"";"";"}' june2021-no30.csv > 4dnd

其中 ~/2021-06-[012]/ 匹配 2021 年 6 月 1 日至(包括)29 日的所有日期。

第二部分 substring(,length()-1)%7==2 负责过滤星期三 (2,9,16,23)