行の最大値を含むCSVファイルから列名(タイトル)を抽出するには?

行の最大値を含むCSVファイルから列名(タイトル)を抽出するには?

Bashスクリプトを使用して、各行の最大値(列ヘッダー値または最初の行の同じ列値)を使用して列名を抽出しようとしています。次のコマンドを使用してCSVファイルの各行から最大値を抽出していますが、最大値で列名を印刷する方法が見つかりませんでした。

awk -F ',' '{max=$'$col1';for (i=1;i<=NF;i++) {if ($i > max){max=$i}};print " max: " max}' "$INPUT_PATH/tmp.csv" >>$INPUT_PATH/max1.csv

例:

サンプルCSVデータ:

col1,col2,col3,col4
1,5,2,6
4,0,1,2
1,2,0,0
0,0,7,0

希望の出力:

col4 6 2
col1 4 1
col2 2 2
col3 7 3

上記のコマンドにこれを行う方法はありますか、またはCSVファイルから必要な情報を抽出するより良い方法はありますか?

答え1

ミラーの使用(https://github.com/johnkerl/miller)と実行

 mlr --c2n merge-fields -a max -r "^[a-z]" -o value -k  then put '
  for (key, value in $*) {
    if (value == $value_max && key != "value_max") {
        $fieldName=key;
    }
}' then cut -f fieldName,value_max then reorder -f fieldName,value_max input.csv

あなたはやる

col4 6
col1 4
col2 2
col3 7

答え2

使用trdatamash:

tr , '\t' < file.csv | datamash -H max 1-4 | datamash transpose

出力:

max(col1)   4
max(col2)   5
max(col3)   7
max(col4)   6

メモ:

  • 先行が不要な場合は、sed一部を使用して出力をクリーンアップできます。max()

  • 列の数を特に知ることはできませんが、確かに大きな数より少ない場合に置き換え、1-4必要1-1000に応じてゼロを追加します。

  • 正確な数を得るには4$(head -1 file.csv | tr , ' ' | wc -w)または(を使用して)に置き換えます。POSIX殻)$(read x < file.csv; echo ${x##*l};)

    整理と正確な計算により、結果として見苦しいコードは次のようになります。

    tr , '\t' < file.csv | 
    datamash -H max 1-$(read x < file.csv; echo ${x##*l};) | 
    datamash transpose | sed 's/.*(\|)//g'
    

    出力:

    col1    4
    col2    5
    col3    7
    col4    6
    

答え3

mx=0レコードのすべてのフィールドが負の場合、初期値設定ソリューションは失敗します。安全に設定する$1と、フィールドが@Peter.Oのように繰り返されることがあります。

楽しく、カウンターとループを生成するのではなく、配列インデックスをawk繰り返すいくつかのバリエーションがあります。head

awk -F',' '
  NR==1{split($0,head,FS); next}
  {x=1; for  (h in head) if ($h>$x) x=h;print head[x], $x }
' file

出力

col4 6
col1 4
col2 2
col3 7

答え4

CSVの問題は、通常のシェルツールではうまく解析できないことです。彼らはそれをうまくできません。それできるマイナーなケースではできますが、実際にはスクリプト言語が作業ツールです。

私はperlもっ​​と個人的に考えています。

#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new();

open ( my $input, "<", "your_file.csv" ) or die $!;
$csv->column_names( $csv->getline( $input ) );

while ( my $row = $csv->getline_hr( $input ) ) {
    my ( $highest, @rest ) = sort { $row->{$b} <=> $row->{$a} } keys %$row;
    print join( "\t", $highest, $row->{$highest} ), "\n";
}

入力として使用される場合:

first,second,third,fourth
1,3,4,5,
5,4,3,2,
1,1,4,1,

以下を印刷します。

fourth  5
first   5
third   4

関連情報