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)
我有一个包含 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)