親愛的大家我有一個大的數據檔可以說文件.dat,它包含兩列
例如 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}'
另一個問題是您min
使用幻數進行初始化(我引用的第一個程式碼中為 9,第二段程式碼中為 0;如果在計算中使用未明確初始化的變量,則其值為 0)。如果這個幻數不在實際資料的數字範圍內,那麼計算出的最小值和/或最大值將是錯誤的。最好將 min 和 max 都初始化為資料中找到的某個值。
保持對...的跟踪兩個都最小值和最大值,您需要兩個變量,並且需要根據文件中的每一行資料檢查這兩個變量,以查看它們是否需要更新。
由於awk
支援數組,因此將數組用於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
從一開始就為零(邏輯上錯誤的),但將被設定為一(邏輯上真的)一旦讀取到第一行資料。
該變數在我們初始化和值的行上nf
被初始化為NF
(字段數)。這樣即使最後一行的欄位為零,區塊中的輸出也能正常運作。min
max
END
答案2
實際上,您可以將所有指令合併到一個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}'