첫 번째 열의 값이 동일한 탭 구분 txt 파일의 두 번째 및 세 번째 열에서 값/단어 발생 횟수를 계산하고 싶습니다.
입력 파일:
GeneA Pathogenic snp
GeneA Pathogenic snp
GeneA Benign indel
GeneA Likely_pathogenic snp
GeneA Pathogenic indel
GeneB Benign snp
GeneB Pathogenic snp
GeneB Benign indel
GeneC Benign snp
GeneC Likely_pathogenic snp
예상 출력: (테이블 형식)
| Pathogenic | Benign | Likely_Pathogenic | snp | indel |
------------|--------|-------------------|-----|-------|
|GeneA| 3| 1| 1| 3| 2|
|GeneB| 1| 2| 0| 2| 1|
|GeneC| 0| 1| 1| 2| 0|
답변1
아래 표시된 스크립트는 awk
지정된 파일에서 데이터를 수집하고 각 "이름"(첫 번째 열)에서 각 "유형"(두 번째 열 이상)의 발생 횟수를 계산합니다. 모든 입력 데이터에 쉼표가 포함되어 있지 않다는 가정하에 다른 프로그램으로 가져올 수 있는 간단한 CSV와 같은 형식을 출력합니다.
{
genes[$1] = 1
for (i = 2; i <= NF; ++i) {
types[$i] = 1
counts[$1,$i]++
}
}
END {
OFS = ","
$0 = "name"
for (t in types)
$(NF+1) = header[++n] = t
print
for (g in genes) {
$0 = g
for (i = 1; i <= n; ++i)
$(NF+1) = counts[g,header[i]]+0
print
}
}
genes
배열은 types
이름과 유형을 키로 포함하는 연관 배열입니다. 이 counts
배열은 입력에서 특정 이름과 유형이 쌍으로 나타나는 횟수를 계산합니다.
이 END
블록은 제목을 생성하고 출력한 다음 모든 유전자 이름을 반복하고 각 유형에 대해 수집된 개수를 출력합니다.
이것을 테스트해 보세요:
$ awk -f script file
name,indel,Benign,Likely_pathogenic,snp,Pathogenic
GeneA,2,1,1,3,3
GeneB,1,2,0,2,1
GeneC,0,1,1,2,0
$ awk -f script file | column -t -s,
name indel Benign Likely_pathogenic snp Pathogenic
GeneA 2 1 1 3 3
GeneB 1 2 0 2 1
GeneC 0 1 1 2 0
$ awk -f script file | csvlook
| name | indel | Benign | Likely_pathogenic | snp | Pathogenic |
| ----- | ----- | ------ | ----------------- | --- | ---------- |
| GeneA | 2 | 1 | True | 3 | 3 |
| GeneB | 1 | 2 | False | 2 | 1 |
| GeneC | 0 | 1 | True | 2 | 0 |
(원치 않으시면csvlook
데이터에서 유형을 추론하려면 해당 데이터와 해당 -I
옵션을 사용하세요. )
답변2
댓글 상자에서 말했듯이 Ruby가 허용되며 다른 프로그램을 파이핑할 필요가 없는 독립형 솔루션이 있습니다.
프로그램
data = <<~'EOF'
GeneA Pathogenic snp
GeneA Pathogenic snp
GeneA Benign indel
GeneA Likely_pathogenic snp
GeneA Pathogenic indel
GeneB Benign snp
GeneB Pathogenic snp
GeneB Benign indel
GeneC Benign snp
GeneC Likely_pathogenic snp
EOF
hash, header1, header2 = {}, [], []
data.each_line { |x|
fields = x.split("\s")
field = hash[fields[0].to_sym] ||= [{}, {}]
field[0].merge!(fields[1] => 1) { |key, val1, val2| val1 + val2 }
field[1].merge!(fields[2] => 1) { |key, val1, val2| val1 + val2 }
header1 << fields[1]
header2 << fields[2]
}
headers = header1.tap(&:uniq!).concat(header2.tap(&:uniq!))
header = '| ' + headers.join(' | ') + ' | '
puts header, ?- * header.length
hash.each { |k, v|
v0, v1 = v[0], v[1]
print "| #{k} |"
headers.each_with_index { |x, i|
out = "#{(v0[x] || v1[x]).to_i} |"
print i == 0 ? out.rjust(5) : out.rjust(x.length + 3)
}
puts
}
구현하다:
$ ruby thisFile.rb
산출:
| Pathogenic | Benign | Likely_pathogenic | snp | indel |
----------------------------------------------------------
| GeneA | 3 | 1 | 1 | 3 | 2 |
| GeneB | 1 | 2 | 0 | 2 | 1 |
| GeneC | 0 | 1 | 1 | 2 | 0 |
하드코딩되어 있기 rjust(5)
때문에 소리를 지르실 수도 있습니다 . rjust(x.length + 3)
실제로 이것들은 타겟으로 지정되어 ' | '
있으며 하드코딩되어 있습니다. 공백을 하나 더 추가하면 숫자가 1씩 늘어납니다. 데이터가 변경되어도 깨지지 않습니다.
data <<~EOF...
를 사용하는 대신 를 사용하여 데이터가 포함된 파일을 읽을 수 있습니다. data = (ARGV[0] && File.readable?(ARGV[0])) ? IO.read(ARGV[0]) : ''
여기서 데이터는 인수로 전달된 파일 이름에서 읽습니다. 모든 데이터에 대해 작동해야 하지만 정렬은 헤더를 기반으로 수행됩니다. 이 코드를 약간 수정하면 가장 큰 필드를 기준으로 데이터를 정렬할 수 있습니다. 하지만 이제는 이것이 당신의 일이 될 것이라고 생각합니다.