Jak sortować kolumny na podstawie pierwszego wiersza?


12

Muszę posortować kolumny bardzo dużego zestawu danych (1000 wierszy i 700000 kolumn). Na przykład moje kolumny są losowo ułożone w następujący sposób: col1 col4 col3 col2, i muszę to posortować.

Próbowałem kilka poleceń, ale bez powodzenia.

przykład:

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

W tym przykładzie kropki oznaczają, że mam dużo kolumn i linii. Ponownie muszę posortować kolumny, aby wyglądały następująco:

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

Dziękuję Ci


Czy możesz dodać przykład z kilkoma wierszami zestawu danych?
jcbermu

oczekiwany wynik został posortowany tylko w pierwszym wierszu, inne wartości pozostają takie same, dlaczego?
RomanPerekhrest

W rzeczywistości musi podążać za kolumnami, to był błąd w przykładzie. przepraszam
LLVerardo

Potrzebujesz posortować całą kolumnę na podstawie pierwszego wiersza.
LLVerardo

2
Transponuj, sortuj według pierwszej kolumny, transponuj z powrotem.
Satō Katsura,

Odpowiedzi:


10

Z GNU datamashi GNU sort:

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

Działa to dobrze w przypadku „stosunkowo małych” danych. Może, ale nie musi działać z twoim plikiem.

Edycja: Poniższe rozwiązania bez transpozycji powinny mniej obciążać zasoby.


1
Polecenie rs może być lżejszą alternatywą dla datamashnp. rs -T < file_in.csv | sort | rs -T -C' '( rsPowinno być dostępne jako pakiet w systemach opartych na Debianie)
steeldriver

2
FWIW rs(„przekształć tablicę danych”) jest dostępny w systemach podstawowych niektórych 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. W pierwszym wierszu sortujemy numerycznie to drugie ... ostatnie kolumny, używając ich liczbowych części po cyfrze Mwystępującej na początku, przy użyciu dobrze znanego Schwartzian maneuver. To daje nam uporządkowane indeksy, dzięki czemu kolumny wychodzą w porządku numerycznym (M1, M2, M3, ...)
  2. Wszystko, co pozostaje, to użyć tych indeksów pochodzących z, @Iaby zmienić rozmieszczenie @Felementów.
  3. Przypisanie tablicy w formie podwójnego cudzysłowu przekształca ją w ciąg z oddzielonymi spacjami elementów.
  4. -popcja Perla włącza autodruk $_zawartości, -ldodaje newline.

6

Korzystanie z modułu perla Sort :: Naturalnie

dane wejściowe

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

wynik

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 dla najbardziej eleganckiego, nie zakłada zbyt konkretnego prefiksu dla nazw kolumn, rozwiązanie jednoprzebiegowe.
arielf

4

Jeśli masz zainstalowane rsnarzędzie , możesz to zrobić:

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

Lub wszystko w jednej linii:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • Pierwszy rstransponuje dane wejściowe (z polami o odstępach spacji)
  • Grupa poleceń:
    • sedczyta pierwszy wiersz, wysyła go, a następnie kończy pracę, pozostawiając resztę potoku rsnietkniętą. stdbufjest wymagane, aby upewnić się, że sedtylko czyta do pierwszej nowej linii, a nie dalej, poprzez wyłączenie buforowania danych wejściowych
    • sorts pozostałe linie
  • Drugi rstransponuje wynikowy strumień z powrotem do oryginalnego formatu.

rsjest instalowany domyślnie na MacOS. W systemach Linux może być konieczne jego zainstalowanie - np

sudo apt install rs

Zastrzeżenie: stdbufi sorts -Vsą specyficzne dla GNU, więc nie będą działać na niezmodyfikowanym MacOS.


0

Jeśli masz GNU awk, możesz spróbować:

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

W Pythonie:

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

Nie wiem, czy uważałeś to za dobrą odpowiedź, ale ...

Dlaczego nie używasz bazy danych do rozwiązania tego problemu? możesz zaimportować zestaw danych jako tabelę tymczasową, a następnie wykonać

WYBIERZ kolumna 1, kolumna 2, ... kolumna-n Z mojej_temp_table

Możesz użyć innych filtrów lub transformacji, jeśli potrzebujesz. Następnie możesz sformatować dane wyjściowe według potrzeb.

Wszystkie te zadania można zaprogramować jako skrypt bash i łączenie danych wyjściowych za pomocą potoków.

Czasami używano polecenia „pv”, aby zobaczyć postęp wyjściowy między poleceniami.

Aby zaimportować zestaw danych, możesz zaprogramować ETL za pomocą integracji danych Pentaho.


0

Może to też może ci pomóc.

  1. Najpierw możesz użyć transpozycji pliku (jeden z /programming/1729824/an-efficient-way-to-transpose-a-file-in-bash )
  2. Sortuj pierwszą kolumnę za pomocą polecenia sortowania.
  3. Transponuj ponownie.

Dawny:

$ 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    
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.