将最大值除以第二大值
Divide largest value by second largest value
我有一个以下格式的文件。第一列有大约 20,000 个 uniq 条目,第二列有大约 120,000 个不同的条目,第三列有与第二列相关联的计数。对于第一列中的单个条目,第二列中可以有多个条目。对于第一列中的每个唯一条目,我我正在尝试获取第 3 列的最大值与第二个最大值的比率。
F1.txt
S1 S2 C1
A A1 1
A AA 10
A A6 5
A A0 4
B BB 12
B BC 11
B B1 19
B B9 4
预期输出
S1 S2 C1
B B1 19 1.58333
A AA 10 2
我可以按照下面的步骤进行。但是有没有一种聪明的方法可以在一个脚本中完成?
awk 'NR==1; NR > 1 {print [=12=] | "sort -k3 -n -r "}' F1.txt | awk '!seen[]++' >del1.txt
awk 'FNR==NR{a[]=1; next}FNR==1{print [=13=];}!a[]' del1.txt F1.txt | awk 'NR==1; NR > 1 {print [=13=] | "sort -k3 -n -r"}' | awk '!seen[]++' >del2.txt
awk 'FNR==NR{a[]=; next}FNR==1{print [=14=]"\t";"RT"}FNR>1 a[]{print [=14=]"\t"/a[]}' del2.txt del1.txt
#!/usr/bin/awk -f
NR == 1 { print , , ; next }
{ data[][] = }
END {
for (key in data) {
asorti(data[key], s, "@ind_num_desc")
print key, data[key][s[1]], s[1], s[1] / s[2]
}
}
这^^^假设行的任意排列(并且需要gawk
(这很常见)或其他使用原生多维“数组”的实现)。
如果您可以对输入做出更多假设——例如它总是按第一列分组 —,那么您可以提高内存效率并摆脱多维数组(通过 not 延迟评估直到 END
而是在每次第一列的值更改时在每行块中计算它(然后最后一次在 END
中)。)
要对相等的数值进行不同的处理(例如,报告第一个(而不是最后一个)出现的值的“子键”(第 2 列),您可以添加 if (!( in data[])) ...
或之类的
每当您发现自己正在创建一个包含 awk
的管道时,您尝试做的事情很有可能可以在一次调用 awk
中更有效地完成。
一种非 GNU awk
方法,假定所有 field1 'A'
记录都在一起并且所有 'B'
记录都在一起( 如您在示例数据中所示) 可能是:
awk '
FNR==1 { print; next } ## 1st line, output heading
!= n { ## 1st field changed
if (n) { ## if n set, output result of last block
printf "%s\t%s\n", rec, max / nextmax
}
rec = [=10=] ## initialize vars for next block
n =
max =
nextmax = 1
next ## skip to next record
}
{
if ( > max) { ## check if 3rd field > max
rec = [=10=] ## save record
nextmax = max ## update nextmax
max = ## update max
}
else if ( > nextmax) { ## if 3rd field > nextmax
nextmax = ## update nextmax
}
} ## output final block results
END { printf "%s\t%s\n", rec, max / nextmax }
' file
例子Use/Output
使用文件 file
中的数据,您将:
$ awk '
> FNR==1 { print; next } ## 1st line, output heading
> != n { ## 1st field changed
> if (n) { ## if n set, output result of last block
> printf "%s\t%s\n", rec, max / nextmax
> }
> rec = [=11=] ## initialize vars for next block
> n =
> max =
> nextmax = 1
> next ## skip to next record
> }
> {
> if ( > max) { ## check if 3rd field > max
> rec = [=11=] ## save record
> nextmax = max ## update nextmax
> max = ## update max
> }
> else if ( > nextmax) { ## if 3rd field > nextmax
> nextmax = ## update nextmax
> }
> } ## output final block results
> END { printf "%s\t%s\n", rec, max / nextmax }
> ' file
S1 S2 C1
A AA 10 2
B B1 19 1.58333
在每个 Unix 机器上使用任何 shell 中的任何 awk 并且几乎不使用内存(这很重要,因为根据您的描述,您的输入文件会很大):
$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == 1 { print; next }
!= prev {
if ( prev != "" ) {
print prev, val, max, (preMax ? max/preMax : 0)
}
prev =
max = ""
}
(max == "") || ( > max) {
val =
preMax = max
max =
}
END { print prev, val, max, (preMax ? max/preMax : 0) }
$ awk -f tst.awk F1.txt
S1 S2 C1
A AA 10 10
B B1 19 1.58333
我有一个以下格式的文件。第一列有大约 20,000 个 uniq 条目,第二列有大约 120,000 个不同的条目,第三列有与第二列相关联的计数。对于第一列中的单个条目,第二列中可以有多个条目。对于第一列中的每个唯一条目,我我正在尝试获取第 3 列的最大值与第二个最大值的比率。
F1.txt
S1 S2 C1
A A1 1
A AA 10
A A6 5
A A0 4
B BB 12
B BC 11
B B1 19
B B9 4
预期输出
S1 S2 C1
B B1 19 1.58333
A AA 10 2
我可以按照下面的步骤进行。但是有没有一种聪明的方法可以在一个脚本中完成?
awk 'NR==1; NR > 1 {print [=12=] | "sort -k3 -n -r "}' F1.txt | awk '!seen[]++' >del1.txt
awk 'FNR==NR{a[]=1; next}FNR==1{print [=13=];}!a[]' del1.txt F1.txt | awk 'NR==1; NR > 1 {print [=13=] | "sort -k3 -n -r"}' | awk '!seen[]++' >del2.txt
awk 'FNR==NR{a[]=; next}FNR==1{print [=14=]"\t";"RT"}FNR>1 a[]{print [=14=]"\t"/a[]}' del2.txt del1.txt
#!/usr/bin/awk -f
NR == 1 { print , , ; next }
{ data[][] = }
END {
for (key in data) {
asorti(data[key], s, "@ind_num_desc")
print key, data[key][s[1]], s[1], s[1] / s[2]
}
}
这^^^假设行的任意排列(并且需要gawk
(这很常见)或其他使用原生多维“数组”的实现)。
如果您可以对输入做出更多假设——例如它总是按第一列分组 —,那么您可以提高内存效率并摆脱多维数组(通过 not 延迟评估直到 END
而是在每次第一列的值更改时在每行块中计算它(然后最后一次在 END
中)。)
要对相等的数值进行不同的处理(例如,报告第一个(而不是最后一个)出现的值的“子键”(第 2 列),您可以添加 if (!( in data[])) ...
或之类的
每当您发现自己正在创建一个包含 awk
的管道时,您尝试做的事情很有可能可以在一次调用 awk
中更有效地完成。
一种非 GNU awk
方法,假定所有 field1 'A'
记录都在一起并且所有 'B'
记录都在一起( 如您在示例数据中所示) 可能是:
awk '
FNR==1 { print; next } ## 1st line, output heading
!= n { ## 1st field changed
if (n) { ## if n set, output result of last block
printf "%s\t%s\n", rec, max / nextmax
}
rec = [=10=] ## initialize vars for next block
n =
max =
nextmax = 1
next ## skip to next record
}
{
if ( > max) { ## check if 3rd field > max
rec = [=10=] ## save record
nextmax = max ## update nextmax
max = ## update max
}
else if ( > nextmax) { ## if 3rd field > nextmax
nextmax = ## update nextmax
}
} ## output final block results
END { printf "%s\t%s\n", rec, max / nextmax }
' file
例子Use/Output
使用文件 file
中的数据,您将:
$ awk '
> FNR==1 { print; next } ## 1st line, output heading
> != n { ## 1st field changed
> if (n) { ## if n set, output result of last block
> printf "%s\t%s\n", rec, max / nextmax
> }
> rec = [=11=] ## initialize vars for next block
> n =
> max =
> nextmax = 1
> next ## skip to next record
> }
> {
> if ( > max) { ## check if 3rd field > max
> rec = [=11=] ## save record
> nextmax = max ## update nextmax
> max = ## update max
> }
> else if ( > nextmax) { ## if 3rd field > nextmax
> nextmax = ## update nextmax
> }
> } ## output final block results
> END { printf "%s\t%s\n", rec, max / nextmax }
> ' file
S1 S2 C1
A AA 10 2
B B1 19 1.58333
在每个 Unix 机器上使用任何 shell 中的任何 awk 并且几乎不使用内存(这很重要,因为根据您的描述,您的输入文件会很大):
$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == 1 { print; next }
!= prev {
if ( prev != "" ) {
print prev, val, max, (preMax ? max/preMax : 0)
}
prev =
max = ""
}
(max == "") || ( > max) {
val =
preMax = max
max =
}
END { print prev, val, max, (preMax ? max/preMax : 0) }
$ awk -f tst.awk F1.txt
S1 S2 C1
A AA 10 10
B B1 19 1.58333