如何从第1列和第2列中提取最大值和最小值

如何从第1列和第2列中提取最大值和最小值

亲爱的大家我有一个大的数据文件可以说文件.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(字段数)。这样即使最后一行的字段为零,块中的输出也能正常工作。minmaxEND

答案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>1NR>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

使用datamashprintf

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}'

相关内容