es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Awk: Cuenta las ocurrencias de valores negativos en cada columna y transpone el CSV.

Estoy intentando escribir un script awk que cree una lista de países que tengan un valor negativo en una columna y los cuente:

Datos de ejemplo:

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
Afganistán, 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
Argelia, 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

Resultado deseado:

4 FREEDOM TO MAKE LIFE CHOICES: Afganistán, Albania, Argelia, Argentina
4 GENEROSITY: Afganistán, Albania, Argelia, Argentina
3 DELIVERY QUALITY: Afganistán, Albania, Argelia
2 CONFIDENCE IN NATIONAL GOVERNMENT: Afganistán, Albania
2 DEMOCRATIC QUALITY: Afganistán, Argelia

Mi script (basado en una respuesta previa de icarus en U&L):

#!/usr/bin/awk -f

BEGIN { FS="," }

NR==1 { for(i=2;i<=NF;i++) { name[i]=$i } ; next } 
{
    for(i=2;i<=NF;i++) {
        v=$i+0
        if (v>0) continue;
        n=name[i]
        cnt[n]++
        cl[n] = cl[n] $1 ","
    }
}

END { 
    for (i in name) {
        n=name[i]   
        printf("%-2d %s: %s\n",cnt[n]+0, n, cl[n] );
    }
} 

Mis problemas son:
1. Mi script no solo cuenta los valores negativos sino que también tiene en cuenta NULL y 0.
2. Me gustaría ordenar la salida por la cuenta, pero no sé cómo hacerlo en la declaración END del script awk.

¿Alguna idea?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para abordar los dos problemas mencionados:

    1. Para modificar el script y contar solo los valores negativos, podemos agregar una condición para verificar si el valor es menor que 0:
    for(i=2;i<=NF;i++) {
        v=$i+0
        if (v<0) {  # solo considerar valores negativos
            n=name[i]
            cnt[n]++
            cl[n] = cl[n]  $1  ","
        }
    }
    

    Esto contará únicamente los valores negativos en las columnas especificadas e ignorará los valores NULL y 0.

    1. Para ordenar la salida por conteo, podemos usar la función asorti en awk. Primero creamos un array count que contiene los conteos para cada columna y luego utilizamos asorti para ordenar los índices (es decir, los nombres de las columnas) según el valor de conteo correspondiente:
    END {
        for (i=2; i<=NF; i++) {
            n = name[i]
            for (j=2; j<=NF; j++) {
                if (name[j] == n) {
                    count[i] += cnt[name[j]]
                }
            }
        }
    
        asorti(count, sorted_idx, "r")  # ordenar los índices en orden descendente (reverso) basado en el conteo
    
        for (i in sorted_idx) {
            n = name[sorted_idx[i]]
            printf("%-2d %s: %s\n", cnt[n], n, cl[n])
        }
    }
    

    Esto mostrará las listas ordenadas por conteo en orden descendente.

Comments are closed.