【发布时间】:2021-06-23 08:24:37
【问题描述】:
我正在处理固定格式排列的多列CSV的后处理:第一列对应行号(ID),第二列包含其人口(POP,样本数落入此ID) 和第三列 (dG) 表示此 ID 的某些固有值(始终为负):
ID, POP, dG
1, 7, -9.6000
2, 3, -8.7700
3, 6, -8.6200
4, 4, -8.2700
5, 6, -8.0800
6, 10, -8.0100
7, 9, -7.9700
8, 8, -7.8400
9, 16, -7.8100
10, 2, -7.7000
11, 1, -7.5600
12, 2, -7.5200
13, 9, -7.5100
14, 1, -7.5000
15, 2, -7.4200
16, 1, -7.3300
17, 1, -7.1700
18, 4, -7.1300
19, 3, -6.9200
20, 1, -6.9200
21, 2, -6.9100
22, 2, -6.8500
23, 10, -6.6900
24, 2, -6.6800
25, 1, -6.6600
26, 20, -6.6500
27, 1, -6.6500
28, 5, -6.5700
29, 3, -6.5500
30, 2, -6.4600
31, 2, -6.4500
32, 1, -6.3000
33, 7, -6.2900
34, 1, -6.2100
35, 1, -6.2000
36, 3, -6.1800
37, 1, -6.1700
38, 4, -6.1300
39, 1, -6.1000
40, 2, -6.0600
41, 3, -6.0600
42, 8, -6.0200
43, 2, -6.0100
44, 1, -6.0100
45, 1, -5.9800
46, 2, -5.9700
47, 1, -5.9300
48, 6, -5.8800
49, 4, -5.8300
50, 4, -5.8000
51, 2, -5.7800
52, 3, -5.7200
53, 1, -5.6600
54, 1, -5.6500
55, 4, -5.6400
56, 2, -5.6300
57, 1, -5.5700
58, 1, -5.5600
59, 1, -5.5200
60, 1, -5.5000
61, 3, -5.4200
62, 4, -5.3600
63, 1, -5.3100
64, 5, -5.2500
65, 5, -5.1600
66, 1, -5.1100
67, 1, -5.0300
68, 1, -4.9700
69, 1, -4.7700
70, 2, -4.6600
为了减少行数,我过滤了这个 CSV,目的是在第二列 (POP) 中搜索编号最高的行,使用以下 AWK 表达式:
# search CSV for the line with the highest POP and save all linnes before it, while keeping minimal number of the linnes (3) in the case if this line is found at the begining of CSV.
awk -v min_lines=3 -F ", " 'a < $2 {for(idx=0; idx < i; idx++) {print arr[idx]} print $0; a=int($2); i=0; printed=NR} a > $2 && NR > 1 {arr[i]=$0; i++}END{if(printed <= min_lines) {for(idx = 0; idx <= min_lines - printed; idx++){print arr[idx]}}}' input.csv > output.csv
对于简单的情况,当具有最大 POP 的字符串位于第一行时,脚本将保存该行 (POP max) +2 行(=min_lines=3)。
对于更复杂的情况,如果具有 POP max 的行位于 CSV 的中间,脚本会检测该行 + 从 CSV 开头的所有前面的行,并在新的 CSV 中列出它们,保持原始顺序.但是,在这种情况下 output.csv 将包含太多行,因为搜索字符串(具有最高 POP)位于第 26 行:
ID, POP, dG
1, 7, -9.6000
2, 3, -8.7700
3, 6, -8.6200
4, 4, -8.2700
5, 6, -8.0800
6, 10, -8.0100
7, 9, -7.9700
8, 8, -7.8400
9, 16, -7.8100
10, 2, -7.7000
11, 1, -7.5600
12, 2, -7.5200
13, 9, -7.5100
14, 1, -7.5000
15, 2, -7.4200
16, 1, -7.3300
17, 1, -7.1700
18, 4, -7.1300
19, 3, -6.9200
20, 1, -6.9200
21, 2, -6.9100
22, 2, -6.8500
23, 10, -6.6900
24, 2, -6.6800
25, 1, -6.6600
26, 20, -6.6500
为了将输出 CSV 中的总行数减少到 3-5 行,如何自定义我的过滤器以仅保存差异很小的行(例如pop 列应该匹配 (POP >0.5 max(POP)) ,同时将每一行与 POP 列中具有最大值的行进行比较?最后,我需要始终保留第一行以及输出中具有最大值的行。所以 AWK 的解决方案应该按以下方式过滤多字符串 CSV(请忽略#中的注释):
ID, POP, dG
1, 7, -9.6000
9, 16, -7.8100
26, 20, -6.6500 # this is POP max detected over all lines
【问题讨论】:
-
但是为什么
6, 10, -8.0100不在输入中,因为10正好是20的50%? -
问题似乎不一致或缺乏细节。您究竟希望结果在 3-5 行中如何?保留 POP ≤ 0.5 max(POP) 的记录不会导致您发布的输出,因为它只会删除第 9 条记录。
-
感谢指正!事实上,我的意思是我需要在输出中保留 pop D 接近 pop MAX (POP > 0.5 max(POP)) 的行,所以它不适合 POP= 10 的行,但肯定会占用第 9 行( POP=16),如预期输出所示。
-
请将您的示例简化为minimal reproducible example。任何带有滚动条的示例输入/输出都不是最小的,因此浪费我们的时间试图理解它。使用 10 行输入而不是 70 行输入,您可能会演示您寻求帮助的任何问题。