如何使用python和gnu-parallel在输出处理测试中只保留一行header?

How to keep only one header row in output processing test using python and gnu-parallel?

问题

我经常需要处理包含多个 CSV 文件的目录并生成一个输出文件。通常,我依赖 GNU 并行处理 运行 这些任务。但是,我需要一种方法来丢弃 returns 输出的第一个作业以外的所有作业的第一行 (header)。

为了使这个具体化,想象一个像这样的几个 CSV 文件的目录...

x,y
1,1.2
2,5.3
3,6.0

然后,有一些 (Python) 脚本,称之为 calc.py,用于清理数据或进行计算...

import csv
import math
import sys

rdr = csv.DictReader(sys.stdin)
wtr = csv.DictWriter(sys.stdout, fieldnames=['x', 'y', 'siny'])
wtr.writeheader()

for row in rdr:
    row['siny'] = math.sin(float(row['y']))
    wtr.writerow(row)

然后我们可以使用 GNU parallel 并行处理数据文件...

parallel --lb python calc.py '<' {} ::: $(ls -1 *.csv)

然而,这将产生多个 header 行。例如...

x,y,siny
1,1.2,0.9320390859672263
2,5.3,-0.8322674422239013
3,6.0,-0.27941549819892586
x,y,siny
4,7.2,0.7936678638491531
5,2.2,0.8084964038195901
6,0.9,0.7833269096274833

我正在寻找一种简单的方法(最好是 parallel 的一个选项)只保留 输出 中的第一个 header 行。手册中与 headers 相关的内容似乎与输入有关。

可能的解决方案

我看到了几个选项,但我都不喜欢其中任何一个...

  1. 不要 calc.py 输出 header 而是在 运行ning 并行之前回显 header。缺点是 header 必须是已知的,否则我们需要在 运行ning [=18= 之前通过 运行ning 之类的 python calc.py data1.csv | head -n 1 来查看 header ].
  2. 将每个作业的输出保存到一个单独的文件中,然后将它们连接起来 post(例如 xsvtailsed 等),从除第一个以外的所有内容中删除 header 。这样做的缺点是必须管理磁盘上的其他文件并在之后清理它们。
  3. 编写另一个程序来执行此操作,并将 parallel 的结果通过管道传递给它。
    • 将输出的每一行与第一行进行比较似乎 CPU 密集,而且我们知道很少有记录会匹配。
    • 假设没有有效的数据记录匹配 header 行。

解决这个问题的最佳方法是什么? 是否有一个选项告诉 parallel 忽略每个作业输出中除一行 header 以外的所有行?

调整选项1如何:

让程序接受两个参数:file jobnumber

if jobnumber == 1:
  output header

要保证首先打印作业 1,请使用 --keep-order:

parallel --keep-order python calc.py {#} '<' {} ::: *.csv

GNU Parallel 会将 运行 作业的输出缓存在 /tmp 中以序列化输出,这可能比 --lb.

慢也可能不慢

一般来说,您可以这样做:

parallel -k python 'calc.py < {} {= uq; $_ = seq()==1 ? "" : "| tail +2" =}' ::: *.csv

uq 自 20190722 起可用。

你会运行一个tail,所以可以稍微慢一点。在我的系统上 tail 每个内核提供 0.5 GB/s。

AFAIK,GNU Parallel 不提供任何此类选项以在输出 header 中仅写入一次

但是一个简单的方法是使用awk只输出header行一次,比如

parallel --lb python calc.py '<' {} ::: $(ls -1 *.csv) | awk 'NR==1 { header=[=10=]; print [=10=]; next; } [=10=] != header'

说明

NR 是 awk 中的行号。当行号为 1 时,它会将其存储在变量 header 中并且只打印一次。如果后面有任何行与 header 完全匹配,它将被忽略

优点

  • 你不需要事先知道header
  • 您不需要将输出保存到单独的文件中
  • 无需更改您的代码

缺点

  • 假设没有数据行完全匹配 header
  • 如果没有 header,它将 trim 第一行和输出的所有相同行
  • 字符串匹配的开销很小