필드의 TRUE 수를 계산하여 필드 번호, TRUE 수 및 레이블(대형 또는 소형) 수를 보고합니다.

필드의 TRUE 수를 계산하여 필드 번호, TRUE 수 및 레이블(대형 또는 소형) 수를 보고합니다.

주어진 열/필드에서 발견된 TRUE 수를 계산하고 해당 열의 TRUE 수와 열 번호를 출력으로 인쇄하는 코드를 Linux 시스템에서 실행하고 있습니다.

새 입력에서 행(입력의 마지막 열)은 "큰" 또는 "작은"(각각 3개 행)으로 지정됩니다.

각 열에서 TRUE가 2개 이상인 "소형"과 "대형"의 수를 계산하고 싶습니다.

2개 이상의 TRUE가 있는 열을 찾는 코드(아래 코드는 입력의 첫 번째 열을 무시한다는 것을 알고 있습니다):

awk -vtc=2 'NR==1{next};
                NR==2{for(i=2;i<=NF;i++){t[i]=0}};
                {for(i=2;i<=NF;i++){if($i=="TRUE"){t[i]++}}}
                END{
                    for(j in t)
                    if(t[j]>=tc){print(j,t[j])}
                }' input.tsv > output.tsv

입력.tsv:

MT MT MT MT MT MT MT MT MT MT
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE

출력.tsv:

(첫 번째 열: 열 번호, 두 번째 열: TRUE 번호)

3 3
6 3
9 2
10 2

새로운 input.tsv

MT MT MT MT MT MT MT MT MT MT CAT
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE LARGE        
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE SMALL         
FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE SMALL        
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE SMALL        
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE LARGE     
FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE LARGE

원하는 출력.tsv:

(세 번째 열: 소수의 TRUE에 할당됨, 4열: 많은 수의 TRUE에 할당됨)

3 3 2 1
6 3 1 2
9 2 1 1
10 2 0 2

도움을 주셔서 대단히 감사합니다, Linux 마법사 여러분!

답변1

(의사) 다차원 배열을 사용한 솔루션awk

awk '
BEGIN {
    b["TRUE"] = 1
    b["FALSE"] = 0
}
FNR > 1 {
    for (i=1; i < NF; ++i)
        a[i, $NF] += b[$i]
}
END {
    s = "SMALL"
    l = "LARGE"
    for (j=1; j<=i; ++j)
        if (a[j, s] || a[j, l])
            print j, a[j, s] + a[j, l],
            a[j, s] + 0,
            a[j, l] + 0
}' input.tsv

또는 GNU awk에서 제공되는 실제 다차원 배열을 사용하십시오.

awk '
FNR > 1 {
    for (i=1; i < NF; ++i)
        if ($i == t)
            ++a[i][$NF] 
}
END {
    for (j in a)
        print j, a[j][s] + a[j][l],
        +a[j][s],
        +a[j][l]
}' t=TRUE s=SMALL l=LARGE input.tsv

답변2

우아한 큰 망치는 아니지만 작동하는 것 같습니다.

#!/bin/bash

cols=$(echo $(head -n 1 file) | awk '{print gsub(/ /, "")}')
sed -e "1d" -e "s/TRUE/1/g" -e "s/FALSE/0/g" -e "s/ /,/g" file > tmp1
sed "/,S.*/d" tmp1 > tmp2
for s in $(seq 1 $cols); do
    tr=$(cut -d, -f$s tmp1 | paste -s -d+ | bc --)
    if [ $tr -gt 0 ]; then
        trl=$(cut -d, -f$s tmp2 | paste -s -d+ | bc --)
        echo $s $tr $(( $tr-$trl )) $trl
    fi
done | column -t -N Col,True,Small,Large
rm tmp1 tmp2

산출

Col  True  Small  Large
3    3     2      1
6    3     1      2
9    2     1      1
10   2     0      2

편집하다

약간 덜 공격적awk

#!/bin/bash

sed -e "1d" -e "s/TRUE/1/g" -e "s/FALSE/0/g" file | awk '{
    for (i=1; i<NF; i++)
        {sumall[i]+= $i; if ($NF == "LARGE") {sumlarge[i]+= $i}};
    } END {
    for (x in sumall)
        if (sumall[x] > 0)
            { print x, sumall[x], sumall[x]-sumlarge[x], sumlarge[x]}
    }' | column -t -N Col,True,Small,Large

답변3

이는 다양한 유틸리티를 호출하는 파이프를 사용합니다.

$ sed -E '1d;s/FALSE/0/g;/LARGE$/s/TRUE/L/g;s/TRUE/S/g' input.tsv |
  datamash transpose |
  perl -F'\t' -lane '$,="\t"; my %h;
    my $c = grep { /^([LS])$/ && ++$h{$1} } @F;
    print $., $c, $h{S}||0, $h{L}||0 if $c > 1;
  '
3   3   2   1
6   3   1   2
9   2   1   1
10  2   0   2

관련 정보