programing

bash에서 열의 고유 값 수 가져오기

jooyons 2023. 6. 29. 20:05
반응형

bash에서 열의 고유 값 수 가져오기

여러 열로 구분된 탭 파일이 있습니다.폴더에 있는 모든 파일에 대해 열에서 서로 다른 값이 발생하는 빈도를 세고 카운트가 감소하는 순서(가장 높은 카운트 우선)로 정렬하려고 합니다.Linux 명령줄 환경에서 이 작업을 수행하려면 어떻게 해야 합니까?

awk, perl, python 등의 공통 명령행 언어를 사용할 수 있습니다.

2열에 대한 주파수 카운트를 보려면(예:

awk -F '\t' '{print $2}' * | sort | uniq -c | sort -nr

파일 A.txt

z    z    a
a    b    c
w    d    e

파일 B.txt

t    r    e
z    d    a
a    g    c

파일 C.txt

z    r    a
v    d    c
a    m    c

결과:

  3 d
  2 r
  1 z
  1 m
  1 g
  1 b

셸에서 수행할 수 있는 방법은 다음과 같습니다.

FIELD=2
cut -f $FIELD * | sort| uniq -c |sort -nr

이것이 바로 bash가 잘하는 종류의 것입니다.

GNU 사이트는 단어와 빈도를 모두 인쇄하는 이 멋진 어색한 스크립트를 제안합니다.

변경 가능성:

  • 파이프로 통과할 수 있습니다.sort -nr(및 그 반대)word그리고.freq[word])을 클릭하여 내림차순으로 결과를 확인합니다.
  • 특정 열이 필요하면 for 루프를 생략하고 간단히 다음과 같이 쓸 수 있습니다.freq[3]++3을 열 번호로 바꿉니다.

다음과 같습니다.

 # wordfreq.awk --- print list of word frequencies

 {
     $0 = tolower($0)    # remove case distinctions
     # remove punctuation
     gsub(/[^[:alnum:]_[:blank:]]/, "", $0)
     for (i = 1; i <= NF; i++)
         freq[$i]++
 }

 END {
     for (word in freq)
         printf "%s\t%d\n", word, freq[word]
 }

이 코드는 모든 열의 발생을 계산하고 각 열의 발생에 대해 정렬된 보고서를 인쇄합니다.

# columnvalues.pl
while (<>) {
    @Fields = split /\s+/;
    for $i ( 0 .. $#Fields ) {
        $result[$i]{$Fields[$i]}++
    };
}
for $j ( 0 .. $#result ) {
    print "column $j:\n";
    @values = keys %{$result[$j]};
    @sorted = sort { $result[$j]{$b} <=> $result[$j]{$a}  ||  $a cmp $b } @values;
    for $k ( @sorted ) {
        print " $k $result[$j]{$k}\n"
    }
}

텍스트를 열 값으로 저장합니다.
실행 방법:perl columnvalues.pl files*

설명.

루프 중 최상위 수준에서:
결합된 입력 파일의 각 행에 대한 루프
줄을 @Fields 배열로 분할
각 열에 대해 결과 해시 배열 데이터 구조를 증가시킵니다.

루프에 대한 최상위 수준:
결과 배열을 반복합니다.
열 번호 인쇄
해당 열에 사용된 값을 가져옵니다.
발생 횟수에 따라 값 정렬
값을 기준으로 한 보조 정렬(예: b vs g vs m vs z)
정렬된 목록을 사용하여 결과 해시를 반복합니다.
각 발생의 값과 수를 인쇄합니다.

@Dennis에서 제공한 샘플 입력 파일을 기반으로 한 결과

column 0:
 a 3
 z 3
 t 1
 v 1
 w 1
column 1:
 d 3
 r 2
 b 1
 g 1
 m 1
 z 1
column 2:
 c 4
 a 3
 e 2

.csv 입력

입력 파일이 .csv인 경우 변경/\s+/로./,/

난독화

보기 흉한 대회에서 펄은 특히 장비가 잘 갖춰져 있습니다.
이 단일 라이너는 다음과 같습니다.

perl -lane 'for $i (0..$#F){$g[$i]{$F[$i]}++};END{for $j (0..$#g){print "$j:";for $k (sort{$g[$j]{$b}<=>$g[$j]{$a}||$a cmp $b} keys %{$g[$j]}){print " $k $g[$j]{$k}"}}}' files*

루비(1.9+)

#!/usr/bin/env ruby
Dir["*"].each do |file|
    h=Hash.new(0)
    open(file).each do |row|
        row.chomp.split("\t").each do |w|
            h[ w ] += 1
        end
    end
    h.sort{|a,b| b[1]<=>a[1] }.each{|x,y| print "#{x}:#{y}\n" }
end

여기를 피함으로써 선형 시간에 접근하는 까다로운 것이 있습니다(그러나 아마도 더 빠르지는 않을 것입니다!).sort그리고.uniq최종 분류를 제외하고는.그것은 ...에 기초를 두고 있습니다. tee그리고.wc대신에!

$ FIELD=2
$ values="$(cut -f $FIELD *)"
$ mkdir /tmp/counts
$ cd /tmp/counts
$ echo | tee -a $values
$ wc -l * | sort -nr
9 total
3 d
2 r
1 z
1 m
1 g
1 b
$

Pure-Bash 버전:

FIELD=1
declare -A results
while read -a line; do
    results[${line[$FIELD]:-(empty)}]=$((results[${line[$FIELD]:-(empty)}]+1));
done < file.txt
echo ${results[@]@A}

키 로직은 연관 배열을 채우는 것입니다. 연관 배열의 키는 파일에 있는 값이고 배열의 값은 발생 횟수입니다.

  • $FIELD한 열 입니다.
  • ${line[$FIELD]} 열 입니다.
  • ${...:-(empty)}빈 값에 대한 특수한 경우입니다(예상보다 적은 열이 있는 경우 어떻게 됩니까?).

출력을 예상 OP 형식으로 정렬하려면 다음 작업이 조금 더 필요합니다.

sort -rn < <(
    for k in "${!results[@]}"; do
        echo "${results[$k]} $k";
    done
)

경고: 탭 구분 및 공백 구분 파일에는 잘 작동하지만 공백이 있는 값에는 잘 작동하지 않습니다.

언급URL : https://stackoverflow.com/questions/4921879/getting-the-count-of-unique-values-in-a-column-in-bash

반응형