Usando awk para identificar el número de columnas idénticas

Usando awk para identificar el número de columnas idénticas

Tengo una gran cantidad de archivos individuales que contienen seis columnas cada uno (el número de filas puede variar). Como un ejemplo sencillo:

1   0   0   0   0   0

0   1   1   1   0   0

Estoy tratando de identificar cuántas columnas únicas tengo (es decir, los números y su orden coinciden), en este caso serían 3.

¿Existe una frase sencilla para hacer esto? Sé que es fácil comparar una columna con otra, pero ¿cómo encontrar columnas idénticas?

Respuesta1

Puede contar las columnas únicas con la siguiente tubería:

$ awk '{for (i=1; i<=NF; ++i) a[i]=a[i]$i; } END { for (i in a) print a[i] }' foo \
  | sort -u | wc -l

El comando awk transpone su entrada, las líneas resultantes se ordenan, solo se mantienen las líneas únicas ( -u) y al final todas las líneas (únicas) (es decir, las columnas transpuestas) se cuentan ( wc -l).

Tenga en cuenta que NFes una variable awk incorporada y se establece automáticamente en la cantidad de campos en el registro actual. $ihace referencia al campo i-ésimo y ENDprotege el siguiente bloque de manera que se ejecute después de que se procesen todos los registros. Awk utiliza por defecto una delimitación de campos en blanco y no en blanco.

Respuesta2

(((...))), pero ¿cómo encontrar columnas idénticas?

$ printf '%s\n' '1 0 0 0 0 0' '0 1 1 1 0 0' | awk -vSUBSEP='=' '
    { for (i=1; i<NF; i++)
        for (j=i+1; j<=NF; j++)
          if ($i==$j)
            M[i,j]++
    }
    END{ for (m in M) if (M[m]==NR) print m }'
5=6
2=3
2=4
3=4

Para todas las columnas i<jde cada fila, incremente M[i,j]siempre que los valores de esas columnas sean iguales. Entonces, M[i,j]==NRdespués de leer NRlas filas, los valores fueron idénticos para todas las filas leídas.

Respuesta3

Esta pregunta me hizo interesante y quise seguir un enfoque que no podía descifrar exactamente y obtuve una ayuda maravillosa.después de publicar como una pregunta diferente. Podría comprender el enfoque que intento seguir a partir de la pregunta que publiqué.

Obtuve 2 soluciones más para este problema (una deGnouc'srespuesta cual es unperlasolución y otra de Juansolución combinada con mi solución).

#The variable appended_input will remove spaces/tabs and just append the rows. 
#Modify the file name in this line. Here I use inputfile as the filename. 

appended_input=$(column -s '\t' inputfile | tr -d '[:space:]') ;

#The array variable will store each column-wise value as an array element.  
#I use sort to find the number of unique elements.

array=($(
    for ((i=0; i<6; i++))
    do
        new=${appended_input:$i:1}
        for ((j=i+6; j<${#appended_input}; j=j+6))
        do 
            new="$new${appended_input:$j:1}"
        done
        echo "$new"
    done
    )) | echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '

Pruebas

Mi archivo de entrada es el siguiente.

1 0 0 1 0 0
0 1 1 0 0 0
1 1 1 1 1 0
1 0 0 1 0 1
1 0 0 1 0 1

Después de ejecutar el script anterior, obtengo el resultado como,

00011 00100 01100 10111

Podría tener wc -wun canal final y obtendría el resultado como solo 4 en lugar de los valores de columna únicos como se muestra arriba.

Respuesta4

Aquí hay una gawksolución que utiliza coprocesos para alimentar cada columna a una instancia separada sha256sume informa el número total de hashes únicos (el número de hashes únicos debe coincidir con el número de columnas únicas dado que la probabilidad de colisión de hash sha256sumes estadísticamente insignificante). Si bien algunos pueden considerar esto como un truco atroz, una ventaja que tiene este enfoque sobre otros es que no intenta concatenar/transponer los datos y, por lo tanto, es relativamente eficiente en memoria.

awk 'BEGIN{for(i=1; i<=6; ++i){s=sprintf("%*s", i+1, ""); a[i]="sha256sum"s}}
    {for (i=1; i<=6; ++i) print $i |& a[i]}
    END{com= "sort | uniq | wc -l"
    for (i=1; i<=6; ++i){close(a[i], "to"); a[i] |& getline x;
    close(a[i]); print x | com};
    close(com)}' file 

información relacionada