将数据转换为列

将数据转换为列
 AC=126;AC_AFR=0;AC_AMR=0;AC_Adj=126;AC_EAS=120;AC_FIN=0;AC_Het=112;
 AC=12683;AC_AFR=4578;AC_AMR=559;AC_Adj=12680;AC_EAS=2104;AC_FIN=501;AC_Het=91966

我的数据其中一列看起来像这样,即键和值。我想将选定的数据转换为列,标题为列中的键和值。

并非所有线路都具有相同的数据。有些行不会有其他行中出现的字段。

想要的输出:

AC      AC_AFR    AC_AMR and so on
126     0         0
12683   4578      559

不确定如何执行此操作或从哪里开始

答案1

这样做的挑战在于,数据不是简单的 CSV 类型文件,其中第一行是列名称,其余行是逐行的列数据。

这里有column_name=column_data,由;字符分隔。我的解决方案是使用Python之类的语言逐行读取文件。我将从每一行创建 dict() ,并为每个字段创建一个 K:V 对。然后我将该字典附加到所有行的 list() 中。

一旦我有了这个,我就可以处理这个列表了。如果我在第一行,我将打印列名,然后打印值,否则我将只打印值。

我认为无论您使用什么语言,该方法都是相似的,但它绝对是可行的。

下面是 Python 中的一个简单示例,它使用 OrderedDicts 来保留“列”顺序:

#!/usr/bin/python
''' a quick example of a script to parse '=' delimited fields in 
    ';' delimited columns of a text file.
    prints tab delimited columnar data with headers to STDOUT
'''
from collections import OrderedDict

with open('data', 'rb') as infile:
    FLINES = infile.read().split()

DATA = []
for line in FLINES:
    fields = line.split(';')
    d = OrderedDict()
    for field in fields:
        if '=' in field:
            col, value = field.split('=')
            d.update({col: value})
    DATA.append(d)

L = 0
for D in DATA:
    if L == 0:
        print '\t'.join(D.keys())
    print '\t'.join(D.values())
    L += 1
  • 此示例假设所有行都具有相同的列,因为它只会打印从列表中获取的第一个条目的 col_names。

答案2

快速而肮脏的解决方案perl

#!/usr/bin/env perl
use strict;
use warnings;

my %cache;
while (<>) {
    chomp;
    for my $pair ( split /;/ ) {
        $pair =~ s/=.*//;
        $cache{$pair} = 1;
    }
}
continue {
    last if eof;
}

my @keys = sort keys %cache;

print +( join "\t", @keys ), "\n";

while (<>) {
    chomp;
    my %h = map { m/([^=]+)=(\S+)/; ( $1, $2 ) } split /;/;
    print +( join "\t", map { $h{$_} // '' } @keys ), "\n";
}

像这样使用它:

perl script.pl input.txt input.txt

这会扫描输入文件两次,首先获取密钥,然后格式化列。它很脏,因为它可能应该使用Text::CSVand Array::Unique

答案3

使用 GNU awk

gawk -F '[=;]' '
    {for (i=1; i<NF; i+=2) values[$i][NR] = $(i+1)}
    END {
        PROCINFO["sorted_in"] = "@ind_str_asc"
        for (key in values) printf "%s\t", key
        print ""
        for (line=1; line<=NR; line++) {
            for (key in values) printf "%s\t", value[key][line]
            print ""
        }
    }
' filename
AC      AC_AFR  AC_AMR  AC_Adj  AC_EAS  AC_FIN  AC_Het  
126     0       0       126     120     0       112 
12683   4578    559     12680   2104    501     91966   

我在这里使用 2 个字段分隔符,因此所有奇数字段都是键,所有偶数字段都是值。

答案4

以下管道使用sedmlr删除任何输入行上的尾随;(如果有),然后将这些行读取为带有;- 分隔字段的记录,其中=用于分隔指示字段名称和字段值的标签。每个记录中字段的顺序对于读取数据并不重要。输出为 TSV。

$ sed 's/;$//' file | mlr --ifs ';' --otsv unsparsify
AC      AC_AFR  AC_AMR  AC_Adj  AC_EAS  AC_FIN  AC_Het
126     0       0       126     120     0       112
12683   4578    559     12680   2104    501     91966

unsparsify的子命令将为mlr缺失字段分配空值(某些记录中存在字段,但其他记录中缺失字段)。

相关内容