각 열의 중복 항목 수 계산

각 열의 중복 항목 수 계산

내 파일에는 100개의 열이 포함되어 있습니다.

다음을 수행해야 합니다.

  • 먼저 각 열의 중복 항목 수를 계산합니다.
  • 그런 다음 행 수(최대에서 최소)별로 출력 열 순서를 표시합니다.

입력 파일:

a     b     c     d     e
11    11    22    56    11
11    44    56    89    11
12    56    78    91    11 
22    60    78          11
22    60    91
      60    98
      91
      91
      95

결과물 파일:

b       c       a       d       e
11      22      11(2)   56      11(4)
44      56      12      89
56      78(2)   22(2)   91
60(3)   91
91(2)   98
95

답변1

GNU awk fo를 사용하는 배열의 배열 합계 sorted_in:

$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == 1 {
    numCols = split($0,tags)
    next
}
{
    for ( colNr=1; colNr<=NF; colNr++ ) {
        val = $colNr
        if ( val != "" ) {
            if ( !seen[colNr][val]++ ) {
                ++colRowNrs[colNr]
            }
            rowNr = colRowNrs[colNr]
            numRows = ( rowNr > numRows ? rowNr : numRows )
            rowColVals[rowNr][colNr] = val
            rowColCnts[rowNr][colNr]++
        }
    }
}
END {
    PROCINFO["sorted_in"] = "@val_num_desc"
    for ( colNr in colRowNrs ) {
        tag = tags[colNr]
        printf "%s%s", tag, (colNr<numCols ? OFS : ORS)
    }
    for ( rowNr=1; rowNr<=numRows; rowNr++ ) {
        for ( colNr in colRowNrs ) {
            val = rowColVals[rowNr][colNr]
            cnt = rowColCnts[rowNr][colNr]
            printf "%s%s%s", val, (cnt > 1 ? "("cnt")" : ""), (colNr<numCols ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk file
b       c       a       d       e
11      22      11(2)   56      11(4)
44      56      12      89
56      78(2)   22(2)   91
60(3)   91
91(2)   98
95

위 내용은 입력 내용이 탭으로 구분되어 있다고 가정합니다. 이것이 잘못된 경우 질문을 편집하여 명확히 하십시오.

답변2

Linux 유틸리티를 사용하는 한 가지 방법이 여기에 나와 있습니다.

if="$PWD/file"
tmp=$(mktemp -d) || exit
cd -- "$tmp"

nf=$(awk -F '\t' '{print NF;exit}' "$if")

printf -v fmt '%%0%dd\n' "$(expr "$nf" : '.*')"

for i in $(seq "$nf"); do
  cut -f"$i" "$if" | 
  grep -E '[^[:space:]]' |
  uniq -c | awk '{$0 = $2 \
   ($1>1 ? "("$1")" : "")}1' \
  > "$(printf "$fmt" "$i")"
done

wc -l * | sed 's/^\s*//;$d' |
sort -k1,1nr -k2 |
 cut -d" " -f2 |
 sed -e '${y/\n/\t/;q;}' -e 'N;H;z;x;D' |
xargs -l  paste | column-t

산출:

b      c      a      d   e
11     22     11(2)  56  11(4)
44     56     12     89  
56     78(2)  22(2)  91  
60(3)  91                
91(2)  98                
95                      

답변3

Perl 데이터 구조를 사용하여 이 문제를 해결할 수 있습니다.

perl -F'/\t/,$_,-1'  -lane '
  $.==1 && do{
    @hdr = @F; next;
  };
  for (0..$#F) {
    my $e = $F[$_];
    next if $e eq "";
    my $main_key = $hdr[$_];
    $h{$main_key}{$e}++;
  }
  }{
  my @AoA =
  map {
    my $key = $hdr[$_];
    my $href = $h{$key};
    local($a,$b);
    [
      $key,
      map {
        my $k = $href->{$_};
        $k > 1 ? qq[$_($k)] : $_;
      }
      sort {
        $a <=> $b
      }
      keys %$href
    ]
  }
  sort {
    keys %{$h{$hdr[$b]}} <=> 
    keys %{$h{$hdr[$a]}} ||
    $a <=> $b
  }
  0..$#hdr;

  # output
  local $, = "\t";
  for (my $i=0; $AoA[0][$i] ne ""; $i++) {
    print map($AoA[$_][$i],0..$#AoA)
  }
' file

산출:

b      c      a      d   e
11     22     11(2)  56  11(4)
44     56     12     89  
56     78(2)  22(2)  91  
60(3)  91                
91(2)  98                
95                       

답변4

열이 행이 되도록 테이블을 바꾸면 작업이 더 쉬워집니다. rs예를 들어 BSD를 사용하여 이 작업을 수행할 수 있습니다.

< yourfile unexpand -t6 | # convert to tsv assumming 6-column wide columns
  rs -nTc | # transpose
  gawk -v OFS='\t' '{
    c=0
    for (i=j=2;++j<=NF+1;)
      if ($i == $j"")
        c++
      else{
        if (c++) $i=$i"("c")"
        $++i=$j
        c=0
      }
    print NF=--i,$0
  }' |
  sort -rn |
  cut -f2- |
  rs -nTc

관련 정보