서로 다른 첫 번째 열을 기반으로 모든 열의 최대값 찾기

서로 다른 첫 번째 열을 기반으로 모든 열의 최대값 찾기

저는 Ubuntu를 사용하고 있으며 다음과 같은 입력 파일이 있습니다.

ifile.dat
1   10  15
3   34  20
1   4   22
3   32  33
5   3   46
2   2   98
4   20  100
3   13  23
4   50  65
1   40  76
2   20  22

어떻게 이를 달성할 수 있나요?

ofile.dat
1   40  76
2   20  98
3   34  33
4   50  100
5   3   46

내 말은 첫 번째 열을 비교하여 각 열의 최대 값을 얻는 것입니다. 감사해요.

내가 시도한 내용은 다음과 같습니다(13개 열이 있는 샘플 파일에서). 하지만 가장 높은 가치는 그렇게 나타나지 않습니다.

cat input.txt | sort -k1,1 -k2,2nr -k3,3nr -k4,4nr -k5,5nr -k6,6nr -k7,7nr -k8,8nr -k9,9nr -k10,10nr -nrk11,11 -nrk12,12 -nrk13,13 | sort -k1,1 -u 

작동하지 않습니다. 도움이 되는 사람이 아래에서 이 문제를 해결하도록 도와주려고 합니다. 하지만 Mac이나 우분투의 gawk에서는 실행할 수 없으며 아래 오류가 표시됩니다.

awk 'BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"} {for(i=2;i<=NF;++i) if (a[$1][i]<$i){a[$1][i]=$i}} END{n=asorti(a, asorted); for(col1 in asorted){print col1, a[col1][2], a[col1][3]}}' input.txt 

오류는 다음과 같습니다

awk: syntax error at source line 1
 context is
    BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"} {for(i=2;i<=NF;++i) if >>>  (a[$1][ <<< 
awk: illegal statement at source line 1
awk: illegal statement at source line 1

BEGIN 문을 제거하고 for 루프를 사용해 보았지만 운이 없었습니다. 감사해요.

추신: stackoverflow에서 이 답변을 얻었습니다. 여기가 유닉스/리눅스 포럼이기 때문에 여기에 글을 게시하게 되었습니다.

답변1

GNU 데이터 혼합다음과 같은 경우에는 괜찮습니다.

$ datamash -sW groupby 1 max 2,3 < ifile.dat 
1   40  76
2   20  98
3   34  33
4   50  100
5   3   46

더 많은 수의 열을 처리하려면 다음을 지정할 수 있습니다.범위예를 들어

datamash -sW groupby 1 max 2-13 < ifile.dat 

답변2

해결책어느열 수(이미 언급한13개 열이 포함된 샘플 파일):

확장된 예제 파일이 있다고 가정합니다.

1   10  15  10  99
3   34  20  20  111
1   4   22  22  33
3   32  33  12  5
5   3   46  44  9
2   2   98  55  55 
4   20  100 11  33
3   13  23  77  23
4   50  65  33  66
1   40  76  78  16
2   20  22  98  93

awk '{ for(i=2;i<=NF;i++) { if (!($1 in a) || $i > a[$1][i]) a[$1][i]=$i }}
     END{ r=""; for(i in a) { r=i; for(j in a[i]) r=r OFS a[i][j]; print r } 
     }' OFS='\t' file

산출:

1   40  76  78  99
2   20  98  98  93
3   34  33  77  111
4   50  100 33  66
5   3   46  44  9

답변3

이것은 awk의 방법입니다.

$ awk '{ 
        if($2 > a[$1][2]){
            a[$1][2] = $2
        } 
        if($3 > a[$1][3]){
            a[$1][3] = $3
        }
       }
  END{
        for(i in a){
            printf "%s ", i; 
            for(c=1; c<=maxFields; c++){
              if(c in a[i]){
                 printf "%s ",a[i][c]
              }
            }
            print ""
        }' ifile.dat 
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46

스크립트는 단순히 2D 배열을 사용하여 a2개 열 각각의 최대값을 저장합니다. 첫 번째 열의 각 값 에 대해 두 번째 열의 최대값 i과 세 번째 열의 최대값이 저장됩니다 . a[i][2]전체 파일을 처리한 후 각 값의 최대값을 인쇄합니다.ia[i][3]i


열이 3개 이상인 경우 다음을 사용할 수 있습니다.

awk '{ 
        for(c=2; c<=NF; c++){
            if($c > a[$1][c]){
                a[$1][c] = $c; 
            }
        }
       } 
       END{
            for(i in a){
                printf "%s: ", i; 
                for(c in a[i]){
                    printf "%s ",a[i][c]
                }
                print ""
            }
        }' ifile.dat 

위의 솔루션은 음수 값에 대해 제대로 작동하지 않거나 등을 사용할 수 있는 경우 배열이 반드시 순서대로 탐색되지 않으므로 0필드 순서가 잘못될 수 있습니다 awk. 보다 강력한 접근 방식은 다음과 같습니다.

awk '{ 
        for(c=2; c<=NF; c++){
            if(!(c in a) || $c > a[$1][c]){
                a[$1][c] = $c; 
            }
        }
      } 
      END{
            for(i in a){
                printf "%s ", i; 
                for(c in a[i]){
                    printf "%s ",a[i][c]
                }
                print ""
            }
         }' ifile.dat 

답변4

파이썬 3 스크립트

#!/usr/bin/env python3
import sys
from collections import OrderedDict as od

# read data in the file first, create data dictionary of column lists
data = od()
with open(sys.argv[1]) as f:
     for line in f:
          columns = line.strip().split()
          how_many = len(columns)-1
          if columns[0] not in data.keys():
              data[ columns[0] ] = [ [] for i in range(how_many) ]
          for index in range(how_many):
              data[ columns[0] ][index].append( int(columns[index+1]) )

# post process all the created lists of lists by applying max() on each
for item in sorted(data.keys()):
    print(item,end=" ") 
    for array in data[item]:
        print(max(array),end=" ")
    print("")

테스트 실행

OP에서 제공하는 입력의 예:

$ ./columns_max.py input.txt                                                                                                                         
1 40 76 
2 20 98 
3 34 33 
4 50 100 
5 3 46 

Roman Perekhrest의 답변에는 확장된 예가 있습니다.

$ ./columns_max.py input.txt                                                                                                                         
1 40 76 78 99 
2 20 98 98 93 
3 34 33 77 111 
4 50 100 33 66 
5 3 46 44 9 

작동 원리:

기본 아이디어는 첫 번째 열 항목으로 사전을 만드는 것입니다. 따라서 사전에는 1, 2, 3, 4 및 5 키가 있습니다. 사전 항목의 각 해당 값은 목록 목록이며, 각 하위 목록은 열에 해당합니다. 따라서 키 1의 경우 두 개의 목록을 포함하는 목록이 있습니다. 첫 번째는 모든 열 2 항목에 대한 것이고 두 번째는 모든 열 3 항목에 대한 것입니다. 기본적으로 다음과 같습니다.

('1', [ ['10', '4', '40'], ['15', '22', '76']] )

이제 이라는 정말 멋진 함수가 있는데 max(), 이를 통해 숫자 목록을 가져와서 그 중에서 가장 큰 항목을 추출할 수 있습니다. 우리가 해야 할 일은 각 키를 반복하고 모든 목록을 가져와서 max()여기에 기능을 적용하는 것뿐입니다.

관련 정보