범위가 정의된 그룹 ID

범위가 정의된 그룹 ID

ID와 숫자(위치)가 포함된 정렬된 파일이 있습니다. 두 번째 열의 위치를 ​​500개 간격의 그룹으로 그룹화해야 합니다.

이 행의 값이 이전 행에 비해 500보다 작으면 동일한 그룹에 배치하고, 이 행의 값이 500보다 크면 다른 그룹에 배치합니다.

입력 파일:

snp00001    200
snp00002    300
snp00003    400
snp00004    500
snp00005    600
snp00006    900
snp00007    1500
snp00008    1800
snp00009    3000
snp00010    3500
snp00011    4000
snp00012    5000

원하는 출력

snp00001 200 Group1
snp00002 300 Group1
snp00003 400 Group1
snp00004 500 Group1
snp00005 600 Group1
snp00006 900 Group1
snp00007 1500 Group2
snp00008 1800 Group2
snp00009 3000 Group3
snp00010 3500 Group3
snp00011 4000 Group4
snp00012 5000 Group5

추가 참고 사항: snp00001 - snp00006은 (snp00002 - snp00001) 또는 (snp00003 - snp00002) 또는 (snp00004 - snp00003)... 사이의 범위가 500 미만이므로 동일한 그룹으로 그룹화됩니다.

snp00006과 snp00007은 사이의 범위(snp00007 - snp00006)가 500보다 크기 때문에 다음 그룹으로 그룹화됩니다.

나는 awk를 시도했지만 성공하지 못했습니다.

awk -v step=500 -v OFS='\t' '{if(NR==1 || $2+limit){group++} file="Group"group; print file,$0}' input_file

답변1

이전 값을 추적하고 현재 값을 저장된 값과 비교해야 합니다. 차이가 500을 초과하는 경우 그룹 수를 늘리십시오.

예를 들어

awk -v group=1 '{if ($2-prev>500) { group++ }} {prev=$2; $3="group" group; print}'
snp00001 200 group1
snp00002 300 group1
snp00003 400 group1
snp00004 500 group1
snp00005 600 group1
snp00006 900 group1
snp00007 1500 group2
snp00008 1800 group2
snp00009 3000 group3
snp00010 3500 group3
snp00011 4000 group3
snp00012 5000 group4

(FWIW, 9/10/11 출력은 일관성이 없습니다. 9->10은 500이지만 그룹을 추가하지 않지만 10->11도 500이지만 그룹을 추가합니다).

답변2

사용행복하다(이전 Perl_6)

이는 유용할 수 있는 약간 다른 그룹화 체계입니다. Raku의 스마트매치 연산자를 사용하여 ~~위치가 범위 내에 있는지 여부를 신속하게 결정합니다.

~$ raku -e 'my $i = 1; my $r = 1..500; for lines() {my $a = .words;  \
            if ($a.[1].Int ~~ $r) {say "$a Group", $i, " ", $r} else {  \
            repeat { $r+=500 } until ($a.[1].Int ~~ $r);  \
            say "$a Group", ++$i, " ", $r };}' file

입력 예:

snp00001    200
snp00002    300
snp00003    400
snp00004    500
snp00005    600
snp00006    900
snp00007    1500
snp00008    1800
snp00009    3000
snp00010    3500
snp00011    4000
snp00012    5000

샘플 출력(뉴클레오티드 1에서 시작하여 500개 뉴클레오티드마다 SNP를 그룹화):

snp00001 200 Group1 1..500
snp00002 300 Group1 1..500
snp00003 400 Group1 1..500
snp00004 500 Group1 1..500
snp00005 600 Group2 501..1000
snp00006 900 Group2 501..1000
snp00007 1500 Group3 1001..1500
snp00008 1800 Group4 1501..2000
snp00009 3000 Group5 2501..3000
snp00010 3500 Group6 3001..3500
snp00011 4000 Group7 3501..4000
snp00012 5000 Group8 4501..5000

위의 Raku 코드는 Group# 반복자 $i와 초기 $r범위를 선언합니다 1..500. 입력은 로 처리되며 lines, 각 줄은 (공백으로 구분됨)로 구분됩니다 words. if/else 조건 실행: if범위, 행, 그룹 번호 및 범위 ~~내의 두 번째 열 스마트 일치 , 범위를 취하고 계속 증가하지만 스마트 일치가 아닌 경우 성공합니다. 그러면 이전과 동일한 정보가 인쇄되지만 이번에는 Group#이 올바르게 증가됩니다( ).$rsayelse$rrepeat500until~~++$i

위의 그룹화 방식의 장점은 결과 그룹이 모두 동일한 길이의 간격(이 경우 약 500개 뉴클레오티드)을 갖는다는 것입니다. 이 체계는 여러 SNP가 약간 함께 위치할 때 발생할 수 있는 그룹 간격 길이의 "확장"을 방지합니다(간격 "확장"은 "클러스터링"이라는 잘못된 인상을 생성할 수 있음).

$m보다 일반적인 "그룹화" 도구로 만들려면 빠른 그룹화를 위해 Range의 오른쪽을 변수( )로 추상화할 수 있습니다 .

~$ raku -e 'my $i=1; my $m=1000; my $r = 1..$m; for lines() {my $a = .words;   if ($a.[1].Int ~~ $r) {say "$a\tGroup$i\t", $r} else { repeat { $r+=$m } until ($a.[1].Int ~~ $r); say "$a\tGroup{++$i}\t", $r };}' file
snp00001 200    Group1  1..1000
snp00002 300    Group1  1..1000
snp00003 400    Group1  1..1000
snp00004 500    Group1  1..1000
snp00005 600    Group1  1..1000
snp00006 900    Group1  1..1000
snp00007 1500   Group2  1001..2000
snp00008 1800   Group2  1001..2000
snp00009 3000   Group3  2001..3000
snp00010 3500   Group4  3001..4000
snp00011 4000   Group4  3001..4000
snp00012 5000   Group5  4001..5000

https://docs.raku.org/type/Range
https://raku.org

관련 정보