awk:各列の各固有文字列の総数とその列の順序で出力

awk:各列の各固有文字列の総数とその列の順序で出力

各列の各uniq文字列の総数(合計)を取得し、その列の順序で出力しようとしています。

さまざまな入力全体が何千もの行と列であることが多いため、強力なawkコマンドでこれを使用する必要があります。

私はこれを自分で試しましたが、運がありませんでした。かなり近いと思います。明らかに動作しませんが、コードを使用する場所は次のとおりです。

awk -F ',' '{ for(N=1; N<=NF; N++) {{count[$N]++} END {for (word in count) print word, count[word]}}}'

上記のコードについての私の考えは、実行すると、指定された単一の列に対して目的の出力を取得できることです。それでは、列2を仮定しましょう。

awk '{count[$2]++} END {for (word in count) print word, count[word]}'

ただし、各列にはこのタイプの出力が必要です。だからこれを達成するために列を繰り返そうとしましたが、失敗しました。

以下は、いくつかのサンプルデータです。

入力例:

M,M,M,M
N,N,N,N    
A,M,G,L
P,P,P,P
A,N,G,L    
P,N,P,L
A,A,A,A
C,C,C,C
A,M,G,C
L,L,L,L
G,G,G,G

対応する予想出力:

M 1,M 2,M 1,M 1
N 1,N 2,N 1,N 1
A 3,A 1,A 1,A 1
P 1,P 1,P 1,P 1
L 1,L 1,L 1,L 3
G 1,G 1,G 3,G 1
C 1,C 1,C 1,C 1

出力を説明するために、入力例の最初の列には3つのAsがあり、他のすべての文字はそれぞれ1つしかないため、その列の出力は次のようになります。
M 1
N 1
A 3
P 1
L 1
G 1
C 1

私はこのコードを書いたがうまくいきますが、理想的にはawkコマンドで実装したいと思います。

for i in $(seq $NumberOfColumns);do
ColumnOutput=$(awk -F ',' -v x=$i '{count[$x]++} END {for (word in count) print word, count[word]}' file)
TotalOutput=$(paste <(echo "$TotalOutput") <(echo "$ColumnOutput") -d ,)
done    
echo "$TotalOutput" | sed 's/^,//g'    

答え1

私はこれが役に立つと思います:

$ awk -F"," '              
    NR==FNR { for (i=1;i<=NF;i++) {a[i,$i]+=1;b[$i]=$i} next }
    { for (i=1;i<=NF;i++)if(b[$1]) printf "%s %s,",$1,a[i,$1];else next; print ""; delete b[$1] }
' file file
M 1,M 3,M 1,M 1,
N 1,N 3,N 1,N 1,
A 4,A 1,A 1,A 1,
P 2,P 1,P 2,P 1,
C 1,C 1,C 1,C 2,
L 1,L 1,L 1,L 3,
G 1,G 1,G 4,G 1,

答え2

使用幸せ(以前のPerl_6)

~$ raku -e 'my @a = [Z] lines.map: *.split(","); my @b; \ 
            for ^@a -> $row  {                          \
                for ^$row.elems -> $col {    my %h;     \
                    %h{$_}++ for @a[$row]>>.[$col];     \
                    @b.push: %h.sort }};                \ 
            for ^@b>>.elems.max -> $j {                 \
                put @b.map({ $_.[$j] // (" " => "0") }).join: "," };'  file

または(より簡単に):

~$ raku -e 'my @a = [Z] lines.map: *.split(","); my @b; \
            for ^@a -> $row {                           \
                my %h is BagHash = @a[$row];            \ 
                @b.push: %h.sort };                     \ 
            for ^@b>>.elems.max -> $j {                 \
                put @b.map({ $_.[$j] // (" " => "0") }).join: "," };'  file

以下は、Perlシリーズのプログラミング言語であるRakuで書いた答えです。 RakuにはUnicodeの高度なサポート機能が組み込まれています。上記のコードは、@署名された配列や署名付き%ハッシュ(辞書とキーと値のペアなど)などのさまざまなPerl機能を利用します。

  • まず、データを1行ずつ読み、lines各データをsplitカンマで区切ります。行と列を置き換えるには、[Z]演算子を使用してデータを@a配列に保存します。

  • 次に、@a配列は最初にby、$row次に繰り返され、$col$rowセルに対して「キー」()がハッシュ(最初の答え)またはBagHash(2番目の答え)$_に格納されます。%h各行が解析された後、キー/値データが配列@bに保存されます。

  • 最後に、maxキー/値の数を決定し(通過)データを出力します。特定の列のキーが未定義の場所にゼロを挿入するように注意してください(OPはここで代わりに使用できます)。elemsput0"Nil"" "

入力例(列のキー数が等しくない):

M,M,M,M
N,N,N,N
A,M,G,L
P,P,P,P
A,N,G,L
P,N,P,L
A,A,A,A
C,C,C,C
A,M,G,X
L,L,L,L
G,G,G,G

出力例(キーと値のペアタブ\tで区切られています):

A  4,A  1,A  1,A  1
C  1,C  1,C  1,C  1
G  1,G  1,G  4,G  1
L  1,L  1,L  1,L  4
M  1,M  3,M  1,M  1
N  1,N  3,N  1,N  1
P  2,P  1,P  2,P  1
   0,   0,   0,X  1

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

関連情報