gpt4 book ai didi

linux - 如何通过匹配标题拆分列?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:07:39 27 4
gpt4 key购买 nike

我在想是否有一种方法可以通过匹配标题来拆分列?

数据是这样的

         ID_1   ID_2   ID_3   ID_6   ID_15
value1 0 2 4 7 6
value2 0 4 4 3 8
value3 2 2 3 7 8

我只想获取 ID_3 和 ID_15 上的列

ID_3   ID_15
4 6
4 8
3 8

如果我知道列的顺序,awk 可以简单地将它分开但是,我有一个非常大的表,手上只有一个ID列表。
我还可以使用 awk 还是在 linux 中有更简单的方法?

最佳答案

输入格式没有明确定义,但有一些简单的方法,awkperlsqlite

(FNR==1) {
nocol=split(col,ocols,/,/) # cols contains named columns
ncols=split("vals " $0,cols) # header line
for (nn=1; nn<=ncols; nn++) colmap[cols[nn]]=nn # map names

OFS="\t" # to align output
for (nn=1; nn<=nocol; nn++) printf("%s%s",ocols[nn],OFS)
printf("\n") # output header line
}
(FNR>1) { # read data
for (nn=1; nn<=nocol; nn++) {
if (nn>1) printf(OFS) # pad
if (ocols[nn] in colmap) { printf("%s",$(colmap[ocols[nn]])) }
else { printf "--" } # named column not in data
}
printf("\n") # wrap line
}

$ nawk -f mycols.awk -v col=ID_3,ID_15 data
ID_3 ID_15
4 6
4 8
3 8

Perl,只是上面的一个变体,带有一些 perl 习语以混淆/娱乐:

use strict;
use warnings;

our @ocols=split(/,/,$ENV{cols}); # cols contains named columns
our $nocol=scalar(@ocols);
our ($nn,%colmap);
$,="\t"; # OFS equiv

# while (<>) {...} implicit with perl -an
if ($. == 1) { # FNR equiv
%colmap = map { $F[$_] => $_+1 } 0..$#F ; # create name map hash
$colmap{vals}=0; # name anon 1st col
print @ocols,"\n"; # output header
} else {
for ($nn = 0; $nn < $nocol; $nn++) {
print "\t" if ($nn>0);
if (exists($colmap{$ocols[$nn]})) { printf("%s",$F[$colmap{$ocols[$nn]}]) }
else { printf("--") } # named column not in data
}
printf("\n")
}

$ cols="ID_3,ID_15" perl -an mycols.pl < data

它使用环境变量来跳过解析命令行的工作。它需要 perl 选项 -an 来设置字段拆分和输入读取循环(很像 awk 所做的)。


还有 sqlite(我使用的是 v3.11,我相信 .import 需要 v3.8 或更高版本)。这使用内存中的临时数据库(如果对于内存来说太大,或者对于解析数据的持久副本来说,命名一个文件),并根据第一行自动创建一个表。此处的优点是您可能根本不需要任何脚本,并且只需一次解析开销即可对数据执行多个查询。

如果您有单个 hard-tab 分隔列,则可以跳过下一步,在这种情况下,将 .mode csv 替换为 .mode tab 在下面的 sqlite 示例中。否则,将您的数据转换为合适的 CSV-ish 格式:

nawk -v OFS="," '(FNR==1){$0="vals " $0} {$1=$1;print} < data > data.csv

这会在第一行添加一个虚拟的第一列“vals”,然后将每一行打印为逗号分隔,它通过向 $1 看似毫无意义的赋值来实现这一点,但这会导致 $0 将被重新计算,用 OFS(逗号)替换 FS(空格/制表符)。

$ sqlite3
sqlite> .mode csv
sqlite> .import data.csv mytable
sqlite> .schema mytable
CREATE TABLE mytable(
"vals" TEXT,
"ID_1" TEXT,
"ID_2" TEXT,
"ID_3" TEXT,
"ID_6" TEXT,
"ID_15" TEXT
);
sqlite> select ID_3,ID_15 from mytable;
ID_3,ID_15
4,6
4,8
3,8
sqlite> .mode column
sqlite> select ID_3,ID_15 from mytable;
ID_3 ID_15
---------- ----------
4 6
4 8
3 8

使用 .once.output 将输出发送到文件 ( sqlite docs )。根据需要使用 .headers on.headers off。sqlite 很乐意创建一个未命名的列,因此您不必将名称添加到标题行的第一列,但您需要确保所有输入行和格式的列数相同。

如果您在 .import 期间遇到“预期 X 列但发现 Y”错误,那么您需要为此稍微清理一下数据格式。

关于linux - 如何通过匹配标题拆分列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35792214/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com