Come ordinare le colonne in base alla prima riga?


12

Devo ordinare le colonne di un set di dati molto grande (1000 righe e 700000 colonne). Ad esempio, le mie colonne sono disposte in modo casuale come: col1 col4 col3 col2, e devo ordinarlo.

Ho provato alcuni comandi, ma senza successo.

esempio:

ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln

In questo esempio, punti significa che ho molte colonne e linee. Ancora una volta, ho bisogno di ordinare le colonne in modo che siano:

ID M1 M2 M3 M4 M5 M6 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln

Grazie


Puoi aggiungere un esempio con alcune righe del set di dati?
jcbermu,

il risultato atteso ha solo la prima riga ordinata, altri valori rimangono gli stessi, perché?
RomanPerekhrest,

In realtà, deve seguire le colonne, è stato un errore dell'esempio. scusa
LLVerardo,

È necessario ordinare l'intera colonna in base alla prima riga.
LLVerardo,

2
Trasponi, ordina per prima colonna, trasponi indietro.
Satō Katsura,

Risposte:


10

Con GNU datamashe GNU sort:

datamash transpose -t ' ' -H <file_in.csv | sort -V | datamash transpose -t ' ' -H >file_out.csv

Funziona bene con dati "ragionevolmente piccoli". Potrebbe funzionare o meno con il tuo file.

Modifica: le soluzioni seguenti senza trasposizioni dovrebbero richiedere meno risorse.


1
Il comando rs potrebbe essere un'alternativa più leggera ad datamashes. rs -T < file_in.csv | sort | rs -T -C' '( rsDovrebbe essere disponibile come pacchetto su sistemi basati su Debian)
steeldriver

2
FWIW, rs("rimodella un array di dati") è disponibile nei sistemi di base di alcuni BSD.
Kusalananda

6
perl -pale '
   $. == 1 and
   @I = map  { $_->[1] }
        sort { $a->[0] <=> $b->[0] }
        map  { [ $F[$_] =~ /^M(\d+)$/, $_ ] } 1..$#F;
   $_ = "@F[0, @I]";
' yourlargefile

  1. Per la prima riga, ordiniamo numericamente la sua seconda ... ultima colonna usando le loro porzioni numeriche dopo la cifra che si Mverifica all'inizio, usando il noto Schwartzian maneuver. Questo ci consente di riordinare gli indici in modo che le colonne escano in ordine numerico (M1, M2, M3, ...)
  2. Non resta che utilizzare questi indici provenienti da @Iriorganizzare gli @Felementi.
  3. L'assegnazione dell'array in una forma tra virgolette lo converte in una stringa con spazio separato da elementi.
  4. -pl'opzione per Perl abilita la stampa automatica dei $_contenuti, -ldeve aggiungere il newline.

6

Utilizzando il modulo perl Sort :: Naturalmente

dati in ingresso

ID M2 M5 M8 M1 M3 M9 M700000
A1 m1,2 m1,5 m1,8 m1,1 m1,3 m1,9 m1,7000000
A2 m2,2 m2,5 m2,8 m2,1 m2,3 m2,9 m2,7000000
A3 m3,2 m3,5 m3,8 m3,1 m3,3 m3,9 m3,7000000
A1000 m1000,2 m1000,5 m1000,8 m1000,1 m1000,3 m1000,9 m1000,7000000
perl -MSort::Naturally -lane '
  if ($. == 1) {
    @indices = (0, map  { $_->[0] }
                   sort { ncmp($a->[1], $b->[1]) }
                   map  { [$_, $F[$_]] }
                   1..$#F
               );
    $, = " ";
  }
  print @F[@indices]
' test.data

produzione

ID M1 M2 M3 M5 M8 M9 M700000
A1 m1,1 m1,2 m1,3 m1,5 m1,8 m1,9 m1,7000000
A2 m2,1 m2,2 m2,3 m2,5 m2,8 m2,9 m2,7000000
A3 m3,1 m3,2 m3,3 m3,5 m3,8 m3,9 m3,7000000
A1000 m1000,1 m1000,2 m1000,3 m1000,5 m1000,8 m1000,9 m1000,7000000

+1 per i più eleganti, non assume un prefisso troppo specifico per i nomi di colonna, soluzione a un passaggio.
arielf

4

Se hai installato l' rsutilità , puoi farlo:

rs -c' ' -T | {
    stdbuf -i0 sed "1q"
    sort -V
} | rs -C' ' -T

O tutto su una riga:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • Il primo rstraspone i dati di input (con campi risparmiati dallo spazio)
  • Il gruppo di comandi:
    • sedlegge la prima riga, la emette, quindi si chiude, lasciando rsintatto il resto della pipa . stdbufè necessario per garantire che sedlegga solo fino alla prima riga nuova e non oltre, disattivando il buffer di input
    • sorts le righe rimanenti
  • Il secondo rstraspone il flusso risultante nel suo formato originale.

rsè installato per impostazione predefinita su MacOS. Sui sistemi Linux potrebbe essere necessario installarlo - ad es

sudo apt install rs

Avvertenza: stdbufe l' opzione sorts -Vè specifica per GNU, quindi non funziona su MacOS non modificato.


0

Se hai GNU awk, puoi provare questo:

NR == 1 {
    for (i = 2; i <= NF; i++) {
        columns[substr($i, 2)] = i;
    }
    count = asorti(columns, sorted, "@ind_num_asc");
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" M%s", sorted[i]);
        indx[i] = columns[sorted[i]];
    }
    print "";
    next;
}
{
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" %s", $(indx[i]));
    }
    print "";
}

0

In Python:

from csv import DictReader, DictWriter
with open('in_file.csv') as infile, open('out_file.csv') as outfile:
  reader = DictReader(infile)
  writer = DictReader(outfile, fieldnames=sorted(reader.fieldnames))
  writer.writerows(reader)

0

Non so se hai considerato questa una buona risposta, ma ...

Perché non usi un database per risolvere questo problema? è possibile importare il set di dati come tabella temporanea, quindi eseguire un

SELEZIONA colonna1, colonna2, ... colonna-n DA my_temp_table

Puoi utilizzare un altro filtro o trasformazioni di cui hai bisogno. Quindi, potresti riformattare il tuo output di cui hai bisogno.

Tutte queste attività potrebbero essere programmate come uno script bash e concatenare gli output usando le pipe.

A volte sono stato usato il comando "pv" per vedere l'avanzamento dell'output tra i comandi.

Per importare il set di dati è possibile programmare un ETL utilizzando Pentaho Data Integration.


0

Forse questo potrebbe anche aiutarti.

  1. Per prima cosa puoi usare trasporre il tuo file (uno di /programming/1729824/an-efficient-way-to-transpose-a-file-in-bash )
  2. Ordina la prima colonna con il comando sort.
  3. Trasporre di nuovo.

Ex:

$ echo "ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln" | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}' | sort -n | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}'
ID M1 M2 M3 M5 .....M7000000 M8 M9
Animal1 1 1 0 0 .....1 2 2
Animal2 0 0 1 1 .....0 2 1
Animal3 1 2 2 1 .....0 0 1
.       
.       
.       
.       
Animaln    
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.