使用awk计算行组的个数

  • 本文关键字:awk 计算 使用 awk
  • 更新时间 :
  • 英文 :


我有一个数据集:(file.txt)

X    Y
1    a
2    b
3    c
10   d
11   e
12   f
15   g
20   h     
25   i
30   j
35   k
40   l
41   m
42   n
43   o
46   p

我想添加两列,分别是Up10和Down10,

  • Up10:从(X)到(X-10)行计数。
  • Down10:从(X)到(X+10)
  • 行计数例如:

X    Y    Up10    Down10    
35   k     3        5  
  • 表白;35-10 X=35 X=30 X=25合计=3行
  • Down10
  • ;35+10 X=35 X=40 X=41 X=42 X=42合计= 5行
  • 所需输出:

X    Y    Up10    Down10
1    a     1        5
2    b     2        5
3    c     3        4
10   d     4        5
11   e     5        4
12   f     5        3
15   g     4        3
20   h     5        3
25   i     3        3
30   j     3        3
35   k     3        5
40   l     3        5
41   m     3        4
42   n     4        3
43   o     5        2
46   p     5        1

这是Pierre franois的解决方案:再次感谢@Pierre franois

awk '
BEGIN{OFS="t"; print "XtYtUp10tDown10"}
(NR == FNR) && (FNR > 1){a[$1] = $1 + 0}
(NR > FNR) && (FNR > 1){ 
up = 0; upl = $1 - 10
down = 0; downl = $1 + 10
for (i in a) { i += 0 # tricky: convert i to integer
if ((i >= upl) && (i <= $1)) {up++}
if ((i >= $1) && (i <= downl)) {down++}
}
print $1, $2, up, down;
}
' file.txt file.txt > file-2.txt

但是当我对13GB的数据使用这个命令时,它花费的时间太长了。

我对13GB的数据再次使用了这种方式:

awk 'BEGIN{ FS=OFS="t" }
NR==FNR{a[NR]=$1;next} {x=y=FNR;while(--x in a&&$1-10<a[x]){} while(++y in a&&$1+10>a[y]){} print $0,FNR-x,y-FNR}
' file.txt file.txt > file-2.txt

当file-2.txt达到1.1GB时被冻结。我已经等了好几个小时了,但是我看不到命令的完成和最终的输出文件。

注意:我在谷歌云工作。机器类型e2-highmem-8 (8vcpu, 64gb内存)

单个传递awk,它保留10个最后记录的滑动窗口,并使用它来计算起起落落。为了对称起见,END中应该有deletes,但我想内存中额外的一些数组元素不会有什么不同:

$ awk '
BEGIN {
FS=OFS="t"
}
NR==1 {
print $1,$2,"Up10","Down10"
}
NR>1 {
a[NR]=$1
b[NR]=$2
for(i=NR-9;i<=NR;i++) {
if(a[i]>=a[NR]-10&&i>=2)
up[NR]++
if(a[i]<=a[NR-9]+10&&i>=2)
down[NR-9]++
}
}
NR>10 {
print a[NR-9],b[NR-9],up[NR-9],down[NR-9]
delete a[NR-9]
delete b[NR-9]
delete up[NR-9]
delete down[NR-9]
}
END {
for(nr=NR+1;nr<=NR+9;nr++) {
for(i=nr-9;i<=nr;i++)
if(a[i]<=a[nr-9]+10&&i>=2&&i<=NR)
down[nr-9]++
print a[nr-9],b[nr-9],up[nr-9],down[nr-9]
}
}' file

输出:

X       Y       Up10    Down10
1       a       1       5
2       b       2       5
...
35      k       3       5
...
43      o       5       2
46      p       5       1

使用滑动窗口的另一种单遍方法

awk '
NR == 1 { next } # skip the header
NR == 2 { min = max = cur = 1; X[cur] = $1; Y[cur] = $2; next }
{   X[++max] = $1; Y[max] = $2
if (X[cur] >= $1 - 10) next
for (; X[cur] + 10 < X[max]; ++cur) {
for (; X[min] < X[cur] - 10; ++min) {
delete X[min]
delete Y[min]
}   
print X[cur], Y[cur], cur - min + 1, max - cur
}
}
END {
for (; cur <= max; ++cur) {
for (; X[min] < X[cur] - 10; ++min);
for (i = max; i > cur && X[cur] + 10 < X[i]; --i);
print X[cur], Y[cur], cur - min + 1, i - cur + 1 
}
}
' file

脚本假定X列是按数字顺序排列的。

最新更新