如何计算csv中列子集的平均值?
How to calculate average of subsets of columns in csv?
我有一个非常大的 CSV 文件,如下所示:
# col1 col2 col3
1 1 7 9
2 2 8 10
3 3 9 11
4 4 10 12
5 5 11 13
6 6 12 14
对于所有列,我想计算每个连续两个字段的平均值,然后偏移到下两个字段。例如,在 col1
中 1
和 2
的平均值是结果列的 第一个 单元格,3
和 3
的平均值4
是结果列的 second 单元格。因此,新的列大小是原始 col1
.
的 一半
对于上面提供的示例文件,脚本的输出应如下所示:
# col1 col2 col3
1 1.5 7.5 9.5
2 3.5 9.5 11.5
3 5.5 11.5 13.5
这个问题似乎是一个可以用 AWK 解决的好[问题],但我对使用 AWK 还是个新手。
不胜感激。
可以用awk
来完成。
awk 'BEGIN { OFS = "\t" }
NR ==1 { print; next } # Print header
NR%2==0 { for (i = 2; i <= NF; i++) old[i] = $i; }
NR%2==1 { for (i = 2; i <= NF; i++) $i = ($i + old[i])/2
= (NR-1)/2; print }'
- 将输出字段分隔符设置为制表符。
- 打印 header 行并跳到下一行。
- 对于偶数行,将字段 2 中的值保存到
old
数组的末尾。
- 对于奇数行(第一行之后),计算旧字段值和当前字段值的平均值。设置行号。打印结果。
示例输出:
# col1 col2 col3
1 1.5 7.5 9.5
2 3.5 9.5 11.5
3 5.5 11.5 13.5
对 N 行的组进行泛化
此脚本接受一个参数,该参数是要组合在一起的行数,如果未指定参数则默认为 2。如评论中所述,代码需要将 old
数组值重置为 0,并对值求和而不是赋值。
$ cat x.awk
awk -v N=${1:-2} \
'BEGIN { OFS = "\t" }
NR ==1 { print; next } # Print header
NR%N!=1 { for (i = 2; i <= NF; i++) old[i] += $i }
NR%N==1 { for (i = 2; i <= NF; i++) $i = ($i + old[i])/N
= int((NR-1)/N)
print
for (i = 2; i <= NF; i++) old[i] = 0
}' data
$ cat data
# col1 col2 col3
1 1 7 9
2 2 8 10
3 3 9 11
4 4 10 12
5 5 11 13
6 6 12 14
7 7 14 17
8 8 16 19
9 9 18 22
10 10 20 26
11 11 22 28
12 12 24 29
$ bash x.awk 2
# col1 col2 col3
1 1.5 7.5 9.5
2 3.5 9.5 11.5
3 5.5 11.5 13.5
4 7.5 15 18
5 9.5 19 24
6 11.5 23 28.5
$ bash x.awk 3
# col1 col2 col3
1 2 8 10
2 5 11 13
3 8 16 19.3333
4 11 22 27.6667
$ bash x.awk 4
# col1 col2 col3
1 2.5 8.5 10.5
2 6.5 13.25 15.75
3 10.5 21 26.25
$ bash x.awk 6
# col1 col2 col3
1 3.5 9.5 11.5
2 9.5 19 23.5
$
如果你想在最后打印部分组,添加一个合适的END
块,它需要除以部分行数而不是行数。
我冒昧地概括了 Jonathan Leffler 的回答,以涵盖 Nth
大小的平均值 window 和偏移量的情况。
我写了一个awk
脚本(我叫它avewithoffset
)如下:
#!bin/awk
BEGIN{
FS=OFS="\t";
n=5; }
NR==1 { print; next;}
(NR-1)%n!=0 { for (i = 2; i <= NF; i++) old[i] += $i; }
(NR-1)%n==0 { for (i = 2; i <= NF; i++)
{ $i = ($i + old[i])/n; old[i] = 0; }
= int( (NR-1)/n );
print; }
注意 n=5
.
我向它提供了以下文件:
# col1 col2 col3
1 1 16 31
2 2 17 32
3 3 18 33
4 4 19 34
5 5 20 35
6 6 21 36
7 7 22 37
8 8 23 38
9 9 24 39
10 10 25 40
11 11 26 41
12 12 27 42
13 13 28 43
14 14 29 44
15 15 30 45
生成的文件如下所示:
# col1 col2 col3
1 3 18 33
2 8 23 38
3 13 28 43
我有一个非常大的 CSV 文件,如下所示:
# col1 col2 col3
1 1 7 9
2 2 8 10
3 3 9 11
4 4 10 12
5 5 11 13
6 6 12 14
对于所有列,我想计算每个连续两个字段的平均值,然后偏移到下两个字段。例如,在 col1
中 1
和 2
的平均值是结果列的 第一个 单元格,3
和 3
的平均值4
是结果列的 second 单元格。因此,新的列大小是原始 col1
.
对于上面提供的示例文件,脚本的输出应如下所示:
# col1 col2 col3
1 1.5 7.5 9.5
2 3.5 9.5 11.5
3 5.5 11.5 13.5
这个问题似乎是一个可以用 AWK 解决的好[问题],但我对使用 AWK 还是个新手。
不胜感激。
可以用awk
来完成。
awk 'BEGIN { OFS = "\t" }
NR ==1 { print; next } # Print header
NR%2==0 { for (i = 2; i <= NF; i++) old[i] = $i; }
NR%2==1 { for (i = 2; i <= NF; i++) $i = ($i + old[i])/2
= (NR-1)/2; print }'
- 将输出字段分隔符设置为制表符。
- 打印 header 行并跳到下一行。
- 对于偶数行,将字段 2 中的值保存到
old
数组的末尾。 - 对于奇数行(第一行之后),计算旧字段值和当前字段值的平均值。设置行号。打印结果。
示例输出:
# col1 col2 col3
1 1.5 7.5 9.5
2 3.5 9.5 11.5
3 5.5 11.5 13.5
对 N 行的组进行泛化
此脚本接受一个参数,该参数是要组合在一起的行数,如果未指定参数则默认为 2。如评论中所述,代码需要将 old
数组值重置为 0,并对值求和而不是赋值。
$ cat x.awk
awk -v N=${1:-2} \
'BEGIN { OFS = "\t" }
NR ==1 { print; next } # Print header
NR%N!=1 { for (i = 2; i <= NF; i++) old[i] += $i }
NR%N==1 { for (i = 2; i <= NF; i++) $i = ($i + old[i])/N
= int((NR-1)/N)
print
for (i = 2; i <= NF; i++) old[i] = 0
}' data
$ cat data
# col1 col2 col3
1 1 7 9
2 2 8 10
3 3 9 11
4 4 10 12
5 5 11 13
6 6 12 14
7 7 14 17
8 8 16 19
9 9 18 22
10 10 20 26
11 11 22 28
12 12 24 29
$ bash x.awk 2
# col1 col2 col3
1 1.5 7.5 9.5
2 3.5 9.5 11.5
3 5.5 11.5 13.5
4 7.5 15 18
5 9.5 19 24
6 11.5 23 28.5
$ bash x.awk 3
# col1 col2 col3
1 2 8 10
2 5 11 13
3 8 16 19.3333
4 11 22 27.6667
$ bash x.awk 4
# col1 col2 col3
1 2.5 8.5 10.5
2 6.5 13.25 15.75
3 10.5 21 26.25
$ bash x.awk 6
# col1 col2 col3
1 3.5 9.5 11.5
2 9.5 19 23.5
$
如果你想在最后打印部分组,添加一个合适的END
块,它需要除以部分行数而不是行数。
我冒昧地概括了 Jonathan Leffler 的回答,以涵盖 Nth
大小的平均值 window 和偏移量的情况。
我写了一个awk
脚本(我叫它avewithoffset
)如下:
#!bin/awk
BEGIN{
FS=OFS="\t";
n=5; }
NR==1 { print; next;}
(NR-1)%n!=0 { for (i = 2; i <= NF; i++) old[i] += $i; }
(NR-1)%n==0 { for (i = 2; i <= NF; i++)
{ $i = ($i + old[i])/n; old[i] = 0; }
= int( (NR-1)/n );
print; }
注意 n=5
.
我向它提供了以下文件:
# col1 col2 col3
1 1 16 31
2 2 17 32
3 3 18 33
4 4 19 34
5 5 20 35
6 6 21 36
7 7 22 37
8 8 23 38
9 9 24 39
10 10 25 40
11 11 26 41
12 12 27 42
13 13 28 43
14 14 29 44
15 15 30 45
生成的文件如下所示:
# col1 col2 col3
1 3 18 33
2 8 23 38
3 13 28 43