親愛なる皆様、私は大きいデータファイルではファイル.dat2つの列が含まれています
例: 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 つの変数が必要であり、これら両方をファイル内の各行のデータと照合して、更新が必要かどうかを確認する必要があります。
は配列をサポートしているので、とawk
に配列を使用し、列ごとに 1 つの配列要素を使用するのが自然です。これは、以下のコードで行ったことです。min
max
任意の数の列に一般化:
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
最初からゼロになります(論理的に間違い)が、1に設定されます(論理的には真実) は、データがある最初の行が読み取られるとすぐに実行されます。
変数は、および値を初期化する行で (フィールドの数)nf
に初期化されます。これは、最後の行にフィールドが 0 個であっても、ブロックの出力が機能するようにするためです。NF
min
max
END
答え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
これにより、両方の列の最小値と最大値が最初の行のそれぞれの値で初期化され (条件 を含むルール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
空でない行がすでに見つかったかどうかを確認し、最初の空でない行の内容を使用して、両方の列の現在の最大値/最小値を事前に設定します。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}'