열의 각 부분의 중앙값을 계산하는 방법을 알아보세요.

열의 각 부분의 중앙값을 계산하는 방법을 알아보세요.

다음과 같은 데이터가 있습니다.

111 5
111 6
111 1
222 8
222 9
222 1
222 3
555 9
555 7
555 6

의 각 값에 대해 $1가능하다면 AWK를 사용하여 $2해당 값에 대한 모든 값의 중앙값을 얻고 싶습니다.$1

원하는 출력:

111 5 5
111 6 5
111 1 5
222 8 5.5
222 9 5.5
222 1 5.5
222 3 5.5
555 9 7
555 7 7
555 6 7

$1여기서 5는 5, 6, 1( == 값 ) 의 중앙값이고 111, 5.5는 8, 9, 1, 3의 중앙값입니다.

답변1

모든 UNIX 시스템의 모든 쉘에서 sort+awk를 사용하십시오.

$ cat tst.awk
$1 != prev { if (NR>1) prt(); prev=$1 }
{ vals[++cnt] = $2 }
END { prt() }

function prt(   i,med) {
    med = (vals[int((cnt+1)/2)] + vals[int((cnt/2)+1)]) / 2
    for (i=1; i<=cnt; i++) {
        print prev, vals[i], med
    }
    cnt = 0
}

$ sort -k1,1n -k2,2n file | awk -f tst.awk
111 1 5
111 5 5
111 6 5
222 1 5.5
222 3 5.5
222 8 5.5
222 9 5.5
555 6 7
555 7 7
555 9 7

$2위 코드는 모든 현재 값을 $1명명된 배열에 저장 vals[]한 다음 $1값이 변경되거나 파일의 끝에 도달하면 호출하여 prt()해당 배열의 중앙값을 계산하고 명명된 변수에 저장한 med다음 루프에 인쇄합니다. s 및 의 $1모든 관련 추가 사항 .$2med

출력 행은 위에서 재정렬되었습니다. 이것이 문제라면 먼저 행을 장식하여 원래 순서를 유지한 다음 위에서 sort+awk를 수행한 다음 다시 원래 순서로 정렬하고 마지막으로 장식을 취소할 수 있습니다.

GNU awk가 있고 키 값이 이미 정렬되어 있는 경우 함수 asort()내에서 호출 할 수 있으므로 이전에 prt()호출할 필요가 없습니다 . 정렬이 없으면 모든 것을 배열에 저장한 다음 END 부분에서 정렬할 수 있습니다. 그러나 그림에서 볼 수 있듯이 먼저 호출하는 것이 가장 명확하고 단순하며 효율적이며 이식성이 뛰어납니다.sortawksort

답변2

데이터가 이미 첫 번째 열에서 사전순으로 정렬되어 있고 프로세스 대체를 이해하는 셸을 사용하고 있다고 가정합니다 <(...).

$ join file <( datamash -W groupby 1 median 2 <file )
111 5 5
111 6 5
111 1 5
222 8 5.5
222 9 5.5
222 1 5.5
222 3 5.5
555 9 7
555 7 7
555 6 7

명령 결과를 사용하여 파일의 첫 번째 필드에서 관계형 JOIN 작업을 수행합니다.

datamash -W groupby 1 median 2 <file

이 명령은 첫 번째 필드의 값으로 그룹화된 두 번째 필드의 각 값 집합의 중앙값을 계산합니다. 이 옵션을 사용하면 GNU가 입력을 공백으로 구분된 것으로 처리하도록 -W합니다 .datamash

이 작업의 결과는

111     5
222     5.5
555     7

원하는 결과를 얻으려면 이를 첫 번째 필드의 원본 데이터와 연결하세요.

데이터가 첫 번째 필드에서 아직 정렬되지 않은 경우:

join <( sort -k 1,1n file ) <( datamash -s -W groupby 1 median 2 <file )

첫 번째 필드가 동일한 행이 서로 상대적으로 재정렬되지 않도록 하려면 명령에서 다음을 sort file사용하는지 확인하세요.안정적인정렬 알고리즘. 대부분의 구현에서는 이를 수행하기 위해 sort비표준 옵션을 사용할 수 있습니다 .-s


프로세스 교체가 없는 쉘의 경우:

  • 데이터는 다음과 같이 정렬됩니다.

    datamash -W groupby 1 median 2 <file | join file -
    
  • 데이터를 정렬해야 합니다.

    sort -o file.sorted -k 1,1n file
    datamash -W groupby 1 median 2 <file.sorted | join file.sorted -
    rm -f file.sorted
    

답변3

GNU awk를 사용하여 asort() 함수를 실행하면 데이터 정렬 여부에 관계없이 입력 파일을 첫 번째 처리에서 두 번 처리해야 하며 각 Id 값을 하나로 그룹화한 다음 각각의 중앙값을 계산합니다. 그룹, 두 번째로 파일을 처리할 때 계산된 중앙값을 마지막 열로 인쇄합니다.id대량:

awk -v sep=, 'NR==FNR{ id[$1]=($1 in id ? id[$1] sep : "") $2; next }
     FNR==1 {
                for(x in id){
                    ln=split(id[x], tmp, sep); asort(tmp)
                    id[x]=(ln%2? tmp[int(ln/2)+1]: (tmp[ln/2]+ tmp[ln/2+1])/2 )
                }
            }
{ print $0, id[$1] }' infile infile

관련 정보