一意の値を計算し、結果の値を新しい列として追加します。

一意の値を計算し、結果の値を新しい列として追加します。

大容量のcsvファイルがあり、簡単なランキングを作成したいと思います。

$ cat file.csv
2022-12-01     RED     1     
2022-12-01     RED     1     
2022-12-01     RED     2     
2022-12-01     RED     2     
2022-12-01     RED     2     
2022-12-01     YELLOW     1     
2022-12-01     YELLOW     1     
2022-12-01     YELLOW     2     
2022-12-01     YELLOW     2     
2022-12-01     YELLOW     2     
$ sort file.csv | uniq -c | sort -nr > file_sort.csv
$ cat file_sort.csv 
3 2022-12-01     RED     2     
3 2022-12-01     YELLOW     2     
2 2022-12-01     RED     1     
2 2022-12-01     YELLOW     1     

結果を新しい列として追加したいのですが、次のように既存の$1に追加したいと思います。

$ cut -f1 file_sort.csv
3 2022-12-01
3 2022-12-01
2 2022-12-01
2 2022-12-01

uniq行の値を新しい列として保存する方法はありますか?このように:

$ cut -f1 file_sort.csv
3
3
2
2

答え1

あなたが望むのは、最初のフィールドから最後のフィールドに数字を移動することだけです。これを指定しませんが、cut表示されたコマンドを使用すると、ファイルがタブで区切られていることを意味します。そのuniq -c場合は、出力が空白(表示されていない)で行を埋め、発生後にタブを追加しないことを考えると、次のように簡単に操作できます。

$ sort file.csv | uniq -c | sort -nr | perl -pe 's/^\s+(\d+) (.*)/$2\t$1/' 
2022-12-01  YELLOW  2   3
2022-12-01  RED 2   3
2022-12-01  YELLOW  1   2
2022-12-01  RED 1   2

または以下sedをサポートします-E

$ sort file.csv | uniq -c | sort -nr | sed -E 's/^ *([0-9]*) (.*)/\2\t\1/' 
2022-12-01  YELLOW  2   3
2022-12-01  RED 2   3
2022-12-01  YELLOW  1   2
2022-12-01  RED 1   2

そしてどんなsedでも:

$ sort file.csv | uniq -c | sort -nr | sed 's/^ *\([0-9]*\) \(.*\)/\2\t\1/' 
2022-12-01  YELLOW  2   3
2022-12-01  RED 2   3
2022-12-01  YELLOW  1   2
2022-12-01  RED 1   2

または、数を計算してawk目的の場所にフィールドを追加してから、4番目のフィールドに基づいてソートすることもできます。

$ awk -F'\t' -v OFS='\t' '{ cnt[$0]++ } 
                          END{
                            for(line in cnt){
                              print line,cnt[line]
                            }
                          }' file.csv | sort -nrk4,4 
2022-12-01  YELLOW  2   3
2022-12-01  RED 2   3
2022-12-01  YELLOW  1   2
2022-12-01  RED 1   2

答え2

使用幸せ(以前のPerl_6)

あなたが望むのはBag要素です。この場合、要素は次のとおりですlines

~$ raku -e '.say for lines.Bag;'  file

入力例(タブ区切り):

2022-12-01     RED     1     
2022-12-01     RED     1     
2022-12-01     RED     2     
2022-12-01     RED     2     
2022-12-01     RED     2     
2022-12-01     YELLOW     1     
2022-12-01     YELLOW     1     
2022-12-01     YELLOW     2     
2022-12-01     YELLOW     2     
2022-12-01     YELLOW     2 

出力例:

2022-12-01    RED    2        3
2022-12-01    RED    1        2
2022-12-01    YELLOW    2        3
2022-12-01    YELLOW    1        2

注:ここでの実際の問題は末尾のスペースである可能性があります。trim-trailing各行の右端にスペースを削除する呼び出しを追加できます。

~$ raku -e '.put for lines.map(*.trim-trailing).Bag;' 

#OR

~$ raku -e '.put for lines>>.trim-trailing.Bag;'  

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

答え3

count-distinctMiller()サブコマンドを使用して、mlr入力がタブで区切られ、列見出しがないと想定し、最初の3つのフィールドに一意の値を持つレコード数を計算します。

$ mlr --tsv -N count-distinct -f 1,2,3 file
2022-12-01      RED     1       2
2022-12-01      RED     2       3
2022-12-01      YELLOW  1       2
2022-12-01      YELLOW  2       3

カウントは、フィールドリストの末尾に新しいフィールドとして追加されます。入力をソートする必要はありません。

カウントを最初のフィールドとして使用するには、reorderサブコマンドを使用します。タイトルが出力に表示されない場合でも、ジョブcountで生成された名前付きフィールドを参照できます。count-distinct

$ mlr --tsv -N count-distinct -f 1,2,3 then reorder -f count file
2       2022-12-01      RED     1
3       2022-12-01      RED     2
2       2022-12-01      YELLOW  1
3       2022-12-01      YELLOW  2

答え4

awkコマンドの連想配列のアイデアを使用すると、一意の行数を簡単に計算できます。

$ awk  '{a[$0]++} END {for (i in a) print a[i]"--->",i}' infile

2---> 2022-12-01     YELLOW     2     
3---> 2022-12-01     RED     2     
2---> 2022-12-01     YELLOW     1     
1---> 2022-12-01     YELLOW     2
2---> 2022-12-01     RED     1

関連情報