두 번째 파일의 열 이름을 사용하여 첫 번째 파일의 열 하위 집합 가져오기

두 번째 파일의 열 이름을 사용하여 첫 번째 파일의 열 하위 집합 가져오기

두 개의 텍스트 파일이 있습니다. 첫 번째 파일은 다음과 같이 탭으로 구분된 파일입니다.

chrom   pos ref alt a1  a2  a3  a4
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd

두 번째 파일은 다음과 같습니다.

a1
a4

두 번째 파일에 있는 첫 번째 파일의 열과 첫 번째 파일의 처음 4개 열을 추출하고 싶습니다. 따라서 위의 경우 출력은 다음과 같습니다.

chrom   pos ref alt a1  a4
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd

쉘에서 이 작업을 수행하고 싶습니다. 어떻게 해야 하나요? 내 파일이 여기에 표시된 것보다 크므로 첫 번째 파일에 많은 열이 있습니다.

cut -f 1-4,$(grep -Fwf file2.txt <(head -1 file1.txt)) file1.txt

답변1

perl문제가 없는 경우 :

$ perl -F'\t' -lane 'if(!$#ARGV){ $h{$_}=1; close ARGV if eof; next }
                     @i = grep { exists $h{$F[$_]} } 4..$#F if $.==1;
                     print join "\t", @F[0..3, @i]' f2.txt f1.tsv
chrom   pos ref alt a1  a4
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd

해시 변수는 두 번째 파일의 행을 키로 사용합니다.

그런 다음 grep해시 키에 대해 필드 이름을 테스트하여 TSV 파일의 헤더 행에서 인덱스를 가져오는 데 사용됩니다.

마지막으로 처음 4개 열과 필터링된 인덱스 값이 인쇄에 사용됩니다.

답변2

표준 명령을 사용하여 두 번째 파일(여기서 호출) paste에 쉼표로 구분된 필드 이름 목록을 만들 수 있습니다.file2

$ paste -s -d , - <file2
a1,a4

우리는 그것을 사용할 수 있습니다밀러( mlr), 구조화된 문서(예: TSV 파일)를 처리하기 위한 유틸리티 및 cut첫 번째 파일(여기서 호출됨)에서 처음 4개 필드와 다음의 필드를 추출하는 하위 명령입니다.file2file1

$ mlr --tsv cut -f "chrom,pos,ref,alt,$(paste -s -d , - <file2)" file1
chrom   pos     ref     alt     a1      a4
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd

Miller의 하위 명령을 사용하면 cut필드 이름을 사용하여 추출할 필드를 선택할 수 있습니다. 여기서는 파일의 이름뿐만 아니라 이름별로 처음 4개의 필드를 선택합니다 file2.

cut하위 명령은 쉼표로 끝나는 필드 이름 목록도 허용하므로 이전에 언급한 명령 tr '\n' ',' <file2대신 이를 사용하도록 선택할 수 있습니다.paste


file3예를 들어 다음과 같은 파일에서 유지하려는 필드 인덱스를 얻은 경우 :

5
8

cut... 다음과 같은 표준 명령을 사용하여 필요한 데이터를 추출 할 수 있습니다 .

$ cut -f "1-4,$(paste -s -d , - <file3)" file1
chrom   pos     ref     alt     a1      a4
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd

다소 복잡한 파이프라인을 사용하여 원본 파일에서 숫자 필드 인덱스 목록을 만들 수 있습니다.

$ head -n 1 file1 | tr '\t' '\n' | grep -xF -f file2 -n | cut -d : -f 1 | paste -s -d , -
5,8

이렇게 하면 데이터에서 헤더 행이 추출되고 탭 문자가 줄 바꿈으로 바뀌어 각 필드 이름이 별도의 줄에 표시됩니다. 그런 다음 grep두 번째 파일의 필드 이름에 해당하는 줄 번호를 출력합니다. 이는 양식으로 출력됩니다 5:a1. 여기서 그 앞의 숫자 :는 줄 번호이고 끝에 있는 텍스트는 일치하는 필드 이름입니다.

해당 숫자를 분리하는 데 사용 cut하고 paste명령을 사용하여 모든 필드 색인을 쉼표로 구분된 목록에 넣습니다.

따라서 이 답변의 상단에 있는 명령의 기능을 에뮬레이트하는 전체 명령은 mlr다음과 같습니다.

cut -f "1-4,$(
    head -n 1 file1 | tr '\t' '\n' |
    grep -xF -f file2 -n | cut -d : -f 1 |
    paste -s -d , -
)" file1

답변3

awk를 사용하십시오.

$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == FNR {
    a[$1]
    next
}
FNR == 1 {
    for ( inFldNr=1; inFldNr<=NF; inFldNr++ ) {
        if ( (inFldNr <= 4) || ($inFldNr in a) ) {
            out2in[++numOutFlds] = inFldNr
        }
    }
}
{
    for ( outFldNr=1; outFldNr<=numOutFlds; outFldNr++ ) {
        inFldNr = out2in[outFldNr]
        printf "%s%s", $inFldNr, (outFldNr<numOutFlds ? OFS : ORS)
    }
}

$ awk -f tst.awk file2 file1
chrom   pos     ref     alt     a1      a4
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd
10      12345   C       T       aa      dd

효율성을 위해 file1위의 각 줄은 인쇄하려는 출력 필드 수만큼만 읽혀지므로 입력에 1000개의 필드가 있지만 10개의 필드만 인쇄하려는 경우 각 줄은 그 이상이 아니라 10번 반복됩니다. 1,000개 이상.

답변4

사용행복하다(이전 Perl_6)

~$ raku -e 'my ($header,@a) = lines.map: *.split(/ \s+ /); 
            $header .= list;  my @ind = <a1 a4>; 
            my @col = (0...3, $header.grep( / @ind /, :k ).Slip); 
            put $header[@col].join("\t"); 
            say $_.join("\t") for @a.map: *.[@col];'  data.csv

위 내용은 Perl 계열의 프로그래밍 언어인 Raku로 작성된 답변입니다. Perl과 마찬가지로 Raku는 생물정보학과 같은 분야의 텍스트 구성에 매우 적합합니다.

먼저 Raku의 루틴을 사용하여 데이터를 읽습니다 lines. 이 줄은 split빈 공간에 있습니다. 데이터를 $header스칼라 및 @a배열에 저장하면 Raku는 해당 데이터가 $header첫 번째 행을 차지하고 다음 명령문이 경량에서 으로 $header업그레이드된다는 것을 알고 있습니다 . 이제 필요한 열 이름을 인라인으로 가져와 배열에 저장합니다.Seqlist@ind

grep필요한 열 이름의 헤더를 제공하여 해당 인덱스 위치(값 대신)를 반환 합니다 :k. 그런 다음 @col필요한 처음 4개 열과 그 결과를 사용하여 배열을 만듭니다. 0...3grep결과 Slip는 결합되어(즉, 평면화되어) 간단한 인덱스를 만듭니다.

@array[@index]행을 처리하는 경우 관용구(한 줄 헤더의 경우)를 사용합니다 . 우리는 열을 다루고 있으므로 map배열 요소(예: )로 들어가야 합니다 @a.map: *.[@col]. 마지막으로 데이터가 join탭에 다시 표시되고 출력됩니다 put.

입력 예:

chrom   pos ref alt a1  a2  a3  a4
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd
10  12345   C   T   aa  bb  cc  dd

예제 출력:

chrom   pos ref alt a1  a4
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd

두 파일을 모두 처리하도록 코드를 업그레이드하는 것은 간단합니다. 간단히 경로를 사용하여 @ind인덱스를 생성하면 열 인덱스 파일을 데이터 파일에서 개념적으로 분리하는 데 도움이 됩니다.

my @ind = "/path/to/index.csv".IO.lines;

명령줄에서 데이터를 가져오는 것을 선호하는 경우 Raku는 @*ARGS이를 위한 배열을 제공합니다. Raku의 IO루틴을 사용하여 파일이 원하는 순서대로 입력되는지 확인하세요.

~$ raku -e 'my ($header,@a) = @*ARGS[0].IO.lines.map: *.split(/ \s+ /);
            $header .= list;  my @ind = @*ARGS[1].IO.lines;
            my @col = (0...3, $header.grep( / @ind /, :k ).Slip);
            put $header[@col].join("\t"); 
            say $_.join("\t") for @a.map: *.[@col];'   data.csv  index.csv
chrom   pos ref alt a1  a4
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd
10  12345   C   T   aa  dd

https://docs.raku.org/routine/grep
https://raku.org

관련 정보