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
私のデータの列の1つであるキーと値は次のとおりです。選択したデータをヘッダーが列のキーと値である列に変換したいと思います。
すべての行に同じデータがあるわけではありません。一部の行には他の行に表示されるフィールドがありません。
希望の出力:
AC AC_AFR AC_AMR and so on
126 0 0
12683 4578 559
これを行う方法や開始位置がわかりません。
答え1
問題は、データが最初の行が列名で、残りの行が行ごとの列データである単純なCSVタイプファイルではないことです。
;
これには、文字で区切られたcolumn_name = column_dataがあります。私の解決策は、Pythonのような言語を使用してファイルを1行ずつ読み込むことでした。各行にdict()を作成し、各フィールドにK:Vペアを作成します。次に、その辞書をすべての行のlist()に追加します。
これを行ったら、リストを操作できます。最初の行にある場合は列名を印刷し、値を印刷し、そうでない場合は値のみを印刷します。
どの言語を使用しても、アプローチは似ていると思いますが、確かに可能です。
以下は、「列」の順序を維持するためにOrderedDictsを使用するPythonの簡単な例です。
#!/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_nameのみを印刷するため、すべての行に同じ列があるとします。
答え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
これは入力ファイルを2回スキャンします。まず、キーをインポートしてから列形式を指定します。おそらくText::CSV
andを使用する必要があるため、汚れていました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
次のパイプラインは、入力行から末尾(存在する場合)を取得して削除し、その行を区切りフィールドを持つレコードsed
に読み込みます。ここでは、フィールド名とフィールド値を表すラベルが区別されます。各レコードのフィールドの順序は、データを読み取るために重要ではありません。出力はTSVです。mlr
;
;
=
$ 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
不足しているフィールドにnull値を割り当てます(フィールドは一部のレコードにはありますが、他のレコードには欠落しています)。