열에서 음수 값의 발생 횟수를 계산하고 관련 행 이름을 나열하는 Awk 스크립트

열에서 음수 값의 발생 횟수를 계산하고 관련 행 이름을 나열하는 Awk 스크립트

열에 음수 값이 있는 국가 목록을 생성하고 이를 계산하는 awk 스크립트를 작성하려고 합니다.

견본:

Country, COL2,COL3,COL4,COL5
Poland,  -0.3, 0,   2,  -0.5
Canada,  -1,   1,   1,  -0.4
Italy,    7,  -5,   3,  -0.1
France,   1,   2,  -0.5, 7 
Portugal, 1,   NULL,   4,   1

원하는 출력:

2 COL2, Poland, Canada, 
1 COL3, Italy, 
1 COL4, France, 
3 COL5, Poland, Canada, Italy, 

스크립트 작성을 시작했지만 예상한 결과에 가깝지 않습니다.

#!/usr/bin/bash 

INPUT=./happiness2.csv
OLDIFS=$IFS
IFS=','

awk 'NF==1{next} 
  {country=$1; $1=""; gsub(/[^-]/,"",$0); l=length($0); 
   print country, l;
        }
  }' < $INPUT

누구든지 도와줄 수 있나요?

답변1

하드코딩하는 대신 첫 번째 행에서 열 이름을 읽습니다. 첫 번째 줄의 추가 공백을 제거할 수 있으면 출력을 더 예쁘게 만드는 데 도움이 됩니다.

편집하다:

#!/usr/bin/awk -f
# The arrays are
# name, indexed by column number, the names of the columns taken from the first line.
# cl, indexed by the column name, the list of countries for which
#    this column is negative.
# cnt, indexed by column name, the count of the number of countries.
BEGIN { FS="," }
NR==1 { for(i=2;i<=NF;i++) { name[i]=$i } ; next }
{
    # loop over the columns
    for(i=2;i<=NF;i++) {
        # get the value of the column as a number
        v=$i+0
        # move on to the next column if the value is non negative.
        if (v>=0) continue;
        # get the name of the column
        n=name[i]
        # increment the count and add the country onto the list
        cnt[n]++
        cl[n] = cl[n]  $1  ", "
    }
}
END { # At the end, loop over the results.
      for (i in name) {
        # get the column name
        n=name[i]
        # print out the saved data
        printf("%d %s, %s\n",cnt[n]+0, n, cl[n]); }}

출력 순서는 명확하게 정의되어 있지 않습니다.

일반적으로 누군가 설명을 요청하면 이를 제공하는 것이 도움이 됩니다.

답변2

먼저 아래를 사용하여 쉼표 주위의 모든 공백을 제거합니다 (예를 들어 공백이 포함된 헤더 필드가 있지만 질문에 제공된 데이터에 충분한 경우 sed이 방법을 더 주의 깊게 사용할 수 있습니다 ). csvformat -S파이프라인은 전치된 데이터를 사용하여 datamash각 행에 음수 값이 있는 국가를 출력합니다.

#!/bin/sh

sed 's/ *, */,/g' file |
datamash -t, transpose |
awk -F, '
    BEGIN { OFS = FS }
    NR == 1 { for (i = 2; i <= NF; ++i) h[i] = $i; next }
    {
        nf = split($0,a)
        $0 = a[1]

        for (i = 2; i <= nf; ++i)
            if (a[i] < 0) $(NF+1) = h[i]

        if (NF > 1) print NF-1, $0
    }'

NR == 1코드의 블록은 awk의 첫 번째 입력 줄에 대해서만 실행 됩니다 datamash. 의 출력은 datamash다음과 같습니다.

Country,Poland,Canada,Italy,France,Portugal
COL2,-0.3,-1,7,1,1
COL3,0,1,-5,2,NULL
COL4,2,1,3,-0.5,4
COL5,-0.5,-0.4,-0.1,7,1

이는 배열에 h첫 번째 행의 헤더가 포함된다는 의미입니다.

의 다른 모든 입력 행에 대해 datamash해당 숫자가 음수인 국가로 구성된 출력 레코드를 생성합니다. 이를 위해 입력 라인을 쉼표로 구분하여 배열로 만든 a다음 문자열 중 하나인 $0현재 레코드를 재설정합니다 . 그런 다음 다른 항목을 반복하여 0보다 작은 숫자를 찾을 때마다 현재 레코드의 헤더를 추가합니다.a[1]COLah

그런 다음 현재 레코드의 필드 수(문자열을 나타내는 데 1 빼기 COL)와 레코드 자체를 인쇄합니다.

질문의 데이터 출력을 제공합니다.

2,COL2,Poland,Canada
1,COL3,Italy
1,COL4,France
3,COL5,Poland,Canada,Italy

print마지막 것을 다음으로 변경할 수 있습니다 .

printf "%d\t%s\n", NF-1, $0

...첫 번째 열을 다른 열과 탭으로 구분하려면 다음을 수행하세요.

2       COL2,Poland,Canada
1       COL3,Italy
1       COL4,France
3       COL5,Poland,Canada,Italy

다음을 입력하면,

COUNTRY NAME, SOCIAL SUPPORT, FREEDOM TO MAKE LIFE CHOICES, GENEROSITY, PERCEPTIONS OF CORRUPTION, POSITIVE AFFECT, NEGATIVE AFFECT, CONFIDENCE IN NATIONAL GOVERNMENT, DEMOCRATIC QUALITY, DELIVERY QUALITY
Afghanistan, 0.49, NULL, -0.11, 0.95, 0.49, 0.37, -0.26, -1.88, -1.43
Albania, 0.63, NULL, -0.03, 0.87, 0.66, 0.33, -0.45, 0.29, -0.13
Algeria, 0.80, NULL, -0.19, 0.69, 0.64, 0.34, 0.24, -0.92, -0.81
Argentina, 0.90, NULL, -0.18, 0.84, 0.80, 0.29, 0.30, 0.35, 0.15

...스크립트 생성됨

4,GENEROSITY,Afghanistan,Albania,Algeria,Argentina
2,CONFIDENCE IN NATIONAL GOVERNMENT,Afghanistan,Albania
2,DEMOCRATIC QUALITY,Afghanistan,Algeria
3,DELIVERY QUALITY,Afghanistan,Albania,Algeria

답변3

Icarus의 솔루션을 따르지만 여기서는 열이 오름차순으로 인쇄됩니다.

awk -F ' *, *' '
NR==1{split($0,a);next}
{
  for (i=2; i<=NF; i++)
    if ( $i ~ /^-/ ) {
      col = a[i]
      buf[col] = buf[col] $1 "," OFS
      knt[col]++
    }
}
END {
  for (i=2; i in a; i++) {
    col = a[i]
    if ( knt[col] )
      print knt[col], col",", buf[col]
  }
}
' file

2 COL2, Poland, Canada, 
1 COL3, Italy, 
1 COL4, France, 
3 COL5, Poland, Canada, Italy, 

관련 정보