1列と2列から最大値と最小値を抽出する方法

1列と2列から最大値と最小値を抽出する方法

愛する皆さん、私には一つあります。大きいデータファイルは次のように言えます。ファイル.dat、2つの列が含まれています。

たとえば、file.dat(複数行を表示)

    0.0000  -23.4334
    0.0289  -23.4760
    0.0578  -23.5187
    0.0867  -23.5616
    0.1157  -23.6045
    0.1446  -23.6473
    0.1735  -23.6900
    0.2024  -23.7324
    0.2313  -23.7745
    0.2602  -23.8162
    0.2892  -23.8574
    0.3181  -23.8980
    0.3470  -23.9379
    0.3759  -23.9772
    0.4048  -24.0156
    0.4337  -24.0532
    0.4627  -24.0898
    0.4916  -24.1254
note: data file has a blank line at the end of the file

期待されるパフォーマンス

列(列1など)で最大値と最小値を検索または抽出したいです。

max - 0.4916
min - 0.0000

2列と同じ

max - -23.4334
min - -24.1254

不完全な年(2列には適用されません)

列1の場合

awk 'BEGIN{min=9}{for(i=1;i<=1;i++){min=(min<$i)?min:$i}print min;exit}' file.dat 
0.0000
cat file.dat | awk '{if ($1 > max) max=$1}END{print max}'
0.4916

2列の場合

awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat
-23.4334

cat file.dat | awk '{if ($2 > max) max=$2}END{print max}'
**no output showing**

質問

2列の最小値と最大値を見つけるのに役立ちます。 注:データファイルの末尾に空白行があります。

答え1

コードの問題、

awk 'BEGIN{min=9}{for(i=2;i<=2;i++){min=(min<$i)?min:$i}print min;exit}' file.dat

...exit入力の最初の行を処理した直後に実行する操作です。中間ブロックをトリガーする必要があります。すべてワイヤー。その後、ENDブロックで見つかった値を印刷できます。他のコードスニペットでこれを行うことができます。

awk '{if ($1 > max) max=$1}END{print max}'

もう1つの問題は、min初期化に魔法の数字を使用することです(引用した最初のコードでは9、2番目のコードでは0、明示的に初期化されていない変数が計算に使用される場合、その値は0です)。このマジックナンバーが実際のデータの数値範囲を超えると、計算された最小値および/または最大値が間違ってしまいます。最小値と最大値の両方をデータで見つかった値に初期化するのが最善です。

追跡し続ける...両方最小値と最大値には2つの変数が必要であり、ファイル内の各データ行に対してこれら2つの変数を確認して更新する必要があることを確認する必要があります。

awk配列がサポートされているため、合計に配列を使用するのはmin自然ですmax(1列あたり1つの配列要素)。これが私が以下のコードでやっていることです。


必要な数の列に一般化します。

NF == 0 {
        # Skip any line that does not have data
        next
}

!initialized {
        # Initialize the max and min for each column from the
        # data on the first line of input that has data.
        # Then immediately skip to next line.

        nf = NF

        for (i = 1; i <= nf; ++i)
                max[i] = min[i] = $i

        initialized = 1
        next
}

{
        # Loop over the columns to see if the max and/or min
        # values need updating.

        for (i = 1; i <= nf; ++i) {
                if (max[i] < $i) max[i] = $i
                if (min[i] > $i) min[i] = $i
        }
}

END {
        # Output max and min values for each column.

        for (i = 1; i <= nf; ++i)
                printf("Column %d: min=%s, max=%s\n", i, min[i], max[i])
}

このスクリプトと質問のデータを考慮すると、次のようになります。

$ awk -f script.awk file
Column 1: min=0.0000, max=0.4916
Column 2: min=-24.1254, max=-23.4334

最初のブロック(すべての行で実行されます)の条件NF == 0は、空の行をスキップすることです。このテストは、「この行にデータフィールド(列)がゼロの場合」を意味します。この変数はinitialized最初から0です(論理的に間違った)ですが、1に設定されています(論理的には本物)データの最初の行を読んだ後。

変数は、初期化して値を指定する行で(フィールド数)にnf初期化されます。NFこれにより、最後の行のフィールドがゼロであってもブロックの出力は正常に機能します。minmaxEND

答え2

実際、すべての指示を1つのawkプログラムにまとめることができます。

awk 'NR==1{min1=max1=$1;min2=max2=$2}\
     NR>1 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
            if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
     END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat

最初の行(条件付きルール)の対応する値を使用して、2つの列の最小値と最大値を初期化し、連続行をスキャンしてNR==1その値が現在の最大値より大きいことを確認します。現在の最小値よりそれぞれ(条件付きルール)NR>1

ファイルの末尾に(条件付きルールEND)結果が印刷されます。

気づくこれは次のように仮定します。空行なし。その場合は、条件をNR>1に変更する必要がありますNR>1 && NF>0。空行がある場合最初の前に、使用

awk '!init && NF>0 {init=1; min1=max1=$1; min2=max2=$2} \
     init==1 && NF>0 {if ($1<min1) {min1=$1} else if ($1>max1) {max1=$1};\
                      if ($2<min2) {min2=$2} else if ($2>max2) {max2=$2}; }\
     END{printf("Column1 min: %f\nColumn1 max: %f\nColumn2 min: %f\nColumn2 max:%f\n",min1,max1,min2,max2)}' file.dat

これは変数を使用してinit空でない行が見つかったことを確認し、空でない最初の行の内容を使用して2つの列の現在の最大/最小値を事前設定します。この統計(空でない)行は、init設定時(この初期化以降)の項目にのみ考慮されます。

一般的に言えば、ファイルは必要ではなく、cat結果をawk

答え3

使用datamashそしてprintf

for f in 1 2 ; do  printf 'Column #%s\nmax - %s\nmin - %s\n\n' $f \
                   $(datamash -W max $f min $f < file.dat); done

...またはループはありません。

printf 'Column #%s\nmax - %s\nmin - %s\n\n' \
       $(datamash -W max 1 min 1 max 2 min 2 < file.dat | 
         tr -s '\t' '\n' | paste - - | nl)

出力:

Column #1
max - 0.4916
min - 0

Column #2
max - -23.4334
min - -24.1254

答え4

これは列1で動作します(平均最大値と最小値を計算します)。

sort -n -k 1 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1}  END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'

2列です

sort -n -k 2 file |awk '{SUM+=$1 ; if ( NR == 1) MIN=$1}  END{print "Average - "SUM/NR, "Min time - "MIN,"Max Time - "$1}'

関連情報