Verwenden von awk zum Identifizieren der Anzahl identischer Spalten

Verwenden von awk zum Identifizieren der Anzahl identischer Spalten

Ich habe eine große Anzahl einzelner Dateien, die jeweils sechs Spalten enthalten (Anzahl der Zeilen kann variieren). Ein einfaches Beispiel:

1   0   0   0   0   0

0   1   1   1   0   0

Ich versuche herauszufinden, wie viele eindeutige Spalten ich habe (d. h. Zahlen und deren Reihenfolge stimmen überein), in diesem Fall wären es 3.

Gibt es dafür einen einfachen Einzeiler? Ich weiß, dass es einfach ist, eine Spalte mit einer anderen zu vergleichen, aber wie findet man identische Spalten?

Antwort1

Sie können die eindeutigen Spalten mit dem folgenden Pipe-Befehl zählen:

$ 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

Der awk-Befehl transponiert Ihre Eingabe, die resultierenden Zeilen werden sortiert, nur eindeutige Zeilen werden beibehalten ( -u) und am Ende werden alle (eindeutigen) Zeilen (also die transponierten Spalten) gezählt ( wc -l).

Beachten Sie, dass dies NFeine integrierte awk-Variable ist und automatisch auf die Anzahl der Felder im aktuellen Datensatz gesetzt wird. $iverweist auf das i-te Feld und ENDschützt den folgenden Block so, dass er ausgeführt wird, nachdem alle Datensätze verarbeitet wurden. Awk verwendet standardmäßig die Feldtrennung zwischen Leer- und Nicht-Leerfeldern.

Antwort2

(((...))), aber wie findet man identische Spalten?

$ 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

Inkrementieren Sie alle Spalten i<jjeder Zeile, M[i,j]wenn die Werte dieser Spalten gleich sind. M[i,j]==NRNach dem Lesen NRder Zeilenmittelwerte waren die Werte für alle gelesenen Zeilen also identisch.

Antwort3

Diese Frage hat mich interessiert und ich wollte einen Ansatz verfolgen, den ich nicht genau herausfinden konnte und bekam wunderbare Hilfenachdem ich eine andere Frage gepostet habe. Den Ansatz, den ich zu verfolgen versuche, können Sie anhand der Frage verstehen, die ich gepostet habe.

Ich habe 2 weitere Lösungen für dieses Problem (eine vonGnoucsAntwort, die eineperlLösung und eine weitere von JohnsLösung kombiniert mit meiner Lösung).

#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' ' '

Testen

Meine Eingabedatei ist wie unten.

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

Nach dem Ausführen des obigen Skripts erhalte ich die folgende Ausgabe:

00011 00100 01100 10111

Sie könnten eine wc -wals letzte Pipe haben und würden als Ausgabe nur 4 erhalten, statt der eindeutigen Spaltenwerte wie oben.

Antwort4

Hier ist eine gawkLösung, die Coprozesse verwendet, um jede Spalte einer separaten Instanz von zuzuführen sha256sumund die Gesamtzahl der eindeutigen Hashes angibt (die Anzahl der eindeutigen Hashes sollte mit der Anzahl der eindeutigen Spalten übereinstimmen, da die Wahrscheinlichkeit einer Hash-Kollision mit sha256sumstatistisch unbedeutend ist). Manche mögen dies für einen ungeheuerlichen Hack halten, aber dieser Ansatz hat gegenüber einigen anderen den Vorteil, dass er nicht versucht, die Daten zu verketten/transponieren und daher relativ speichereffizient ist.

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 

verwandte Informationen