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입니다). 이 매직넘버가 실제 데이터의 수치범위를 벗어나면 계산된 최소값 및/또는 최대값이 틀리게 됩니다. 최소값과 최대값을 모두 데이터에서 발견된 값으로 초기화하는 것이 가장 좋습니다.

계속 추적하세요...둘 다최소값과 최대값에는 두 개의 변수가 필요하며 파일의 각 데이터 줄에 대해 이 두 변수를 확인하여 업데이트해야 하는지 확인해야 합니다.

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은 빈 행을 건너뛰는 것입니다. 이 테스트는 "이 행에 데이터 필드(열)가 0개인 경우"를 의미합니다. 이 변수는 initialized처음부터 0입니다(논리적으로잘못된)이지만 1로 설정됩니다(논리적으로는진짜) 데이터의 첫 번째 줄을 읽은 후.

변수는 초기화하고 값을 지정하는 줄에서 (필드 수) nf로 초기화됩니다 . NF이렇게 하면 마지막 행의 필드가 0이더라도 블록의 출력이 제대로 작동합니다.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>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}'

관련 정보