如何使用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 相关的内容似乎与输入有关。
可能的解决方案
我看到了几个选项,但我都不喜欢其中任何一个...
- 不要
calc.py
输出 header 而是在 运行ning 并行之前回显 header。缺点是 header 必须是已知的,否则我们需要在 运行ning [=18= 之前通过 运行ning 之类的 python calc.py data1.csv | head -n 1
来查看 header ].
- 将每个作业的输出保存到一个单独的文件中,然后将它们连接起来 post(例如
xsv
、tail
、sed
等),从除第一个以外的所有内容中删除 header 。这样做的缺点是必须管理磁盘上的其他文件并在之后清理它们。
- 编写另一个程序来执行此操作,并将
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 第一行和输出的所有相同行
- 字符串匹配的开销很小
问题
我经常需要处理包含多个 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 相关的内容似乎与输入有关。
可能的解决方案
我看到了几个选项,但我都不喜欢其中任何一个...
- 不要
calc.py
输出 header 而是在 运行ning 并行之前回显 header。缺点是 header 必须是已知的,否则我们需要在 运行ning [=18= 之前通过 运行ning 之类的python calc.py data1.csv | head -n 1
来查看 header ]. - 将每个作业的输出保存到一个单独的文件中,然后将它们连接起来 post(例如
xsv
、tail
、sed
等),从除第一个以外的所有内容中删除 header 。这样做的缺点是必须管理磁盘上的其他文件并在之后清理它们。 - 编写另一个程序来执行此操作,并将
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 第一行和输出的所有相同行
- 字符串匹配的开销很小