행의 최대값을 포함하는 CSV 파일에서 열 이름(제목)을 추출하는 방법은 무엇입니까?

행의 최대값을 포함하는 CSV 파일에서 열 이름(제목)을 추출하는 방법은 무엇입니까?

Bash 스크립트를 사용하여 각 행의 최대값(열 헤더 값 또는 첫 번째 행의 동일한 열 값)을 사용하여 열 이름을 추출하려고 합니다. 다음 명령을 사용하여 CSV 파일의 각 행에서 최대값을 추출하고 있지만 최대값과 함께 열 이름을 인쇄하는 방법을 찾을 수 없습니다.

awk -F ',' '{max=$'$col1';for (i=1;i<=NF;i++) {if ($i > max){max=$i}};print " max: " max}' "$INPUT_PATH/tmp.csv" >>$INPUT_PATH/max1.csv

예:

샘플 CSV 데이터:

col1,col2,col3,col4
1,5,2,6
4,0,1,2
1,2,0,0
0,0,7,0

원하는 출력:

col4 6 2
col1 4 1
col2 2 2
col3 7 3

위 명령에 이 작업을 수행할 수 있는 방법이 있습니까, 아니면 CSV 파일에서 필요한 정보를 추출하는 더 좋은 방법이 있습니까?

답변1

밀러 사용(https://github.com/johnkerl/miller) 그리고 실행

 mlr --c2n merge-fields -a max -r "^[a-z]" -o value -k  then put '
  for (key, value in $*) {
    if (value == $value_max && key != "value_max") {
        $fieldName=key;
    }
}' then cut -f fieldName,value_max then reorder -f fieldName,value_max input.csv

당신은 할 것

col4 6
col1 4
col2 2
col3 7

답변2

사용 trdatamash:

tr , '\t' < file.csv | datamash -H max 1-4 | datamash transpose

산출:

max(col1)   4
max(col2)   5
max(col3)   7
max(col4)   6

노트:

  • 선행이 필요하지 않은 경우 sed일부를 사용하여 출력을 정리할 수 있습니다.max()

  • 열의 개수를 특별히 알 수는 없지만 확실히 큰 개수보다 적은 경우 로 바꾸고 1-4필요 1-1000에 따라 0을 추가합니다.

  • 정확한 개수를 얻으려면 4, $(head -1 file.csv | tr , ' ' | wc -w)또는 (을 사용하여) 로 바꾸십시오.POSIX껍데기) $(read x < file.csv; echo ${x##*l};).

    정리와 정확한 계산을 통해 결과적으로 보기 흉한 코드는 다음과 같습니다.

    tr , '\t' < file.csv | 
    datamash -H max 1-$(read x < file.csv; echo ${x##*l};) | 
    datamash transpose | sed 's/.*(\|)//g'
    

    산출:

    col1    4
    col2    5
    col3    7
    col4    6
    

답변3

mx=0레코드의 모든 필드가 음수이면 초기 값 설정 솔루션이 실패합니다. 안전하도록 설정 $1하면 필드가 @Peter.O처럼 반복될 수 있습니다.

재미삼아 카운터와 루프를 생성하는 대신 배열 인덱스를 awk반복하는 약간의 변형이 있습니다.head

awk -F',' '
  NR==1{split($0,head,FS); next}
  {x=1; for  (h in head) if ($h>$x) x=h;print head[x], $x }
' file

산출

col4 6
col1 4
col2 2
col3 7

답변4

CSV의 문제점은 일반 쉘 도구로는 잘 구문 분석되지 않는다는 것입니다. 그들은 단지 그것을 잘 하지 못할 뿐입니다. 그것할 수 있는사소한 경우에는 할 수 있지만 실제로는 스크립팅 언어가 작업 도구입니다.

나는 perl좀 더 개인적으로 생각합니다.

#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new();

open ( my $input, "<", "your_file.csv" ) or die $!;
$csv->column_names( $csv->getline( $input ) );

while ( my $row = $csv->getline_hr( $input ) ) {
    my ( $highest, @rest ) = sort { $row->{$b} <=> $row->{$a} } keys %$row;
    print join( "\t", $highest, $row->{$highest} ), "\n";
}

입력으로 사용되는 경우:

first,second,third,fourth
1,3,4,5,
5,4,3,2,
1,1,4,1,

다음을 인쇄합니다:

fourth  5
first   5
third   4

관련 정보