데이터를 열로 변환

데이터를 열로 변환
 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()에 추가합니다.

일단 이것을 갖고 나면 목록 작업을 할 수 있습니다. 첫 번째 행에 있으면 열 이름을 인쇄한 다음 값을 인쇄하고, 그렇지 않으면 값만 인쇄합니다.

어떤 언어를 사용하든 접근 방식은 비슷하다고 생각하지만 확실히 가능합니다.

다음은 "열" 순서를 유지하기 위해 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

이렇게 하면 입력 파일을 두 번 스캔합니다. 먼저 키를 가져온 다음 열 형식을 지정합니다. 아마도 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

다음 파이프라인은 입력 줄에서 후행(있는 경우)을 가져와 제거한 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 값을 할당합니다(필드는 일부 레코드에 있지만 다른 레코드에는 누락됨).

관련 정보