Bagaimana cara mengurutkan kolom berdasarkan baris pertama?


12

Saya perlu mengurutkan kolom dataset yang sangat besar (1000 baris dan 700.000 kolom). Sebagai contoh, kolom saya disusun secara acak seperti: col1 col4 col3 col2, dan saya perlu mengurutkannya.

Saya telah mencoba beberapa perintah, tetapi tidak berhasil.

contoh:

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

Dalam contoh ini, titik-titik berarti saya memiliki banyak kolom dan garis. Sekali lagi, saya perlu mengurutkan kolom menjadi seperti:

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

Terima kasih


Bisakah Anda menambahkan contoh dengan beberapa baris kumpulan data?
jcbermu

hasil yang Anda harapkan hanya diurutkan baris pertama, nilai-nilai lain tetap sama, mengapa?
RomanPerekhrest

Sebenarnya, perlu mengikuti kolom, adalah kesalahan contoh. maaf
LLVerardo

Perlu seluruh kolom untuk diurutkan berdasarkan baris pertama.
LLVerardo

2
Transpos, urutkan berdasarkan kolom pertama, transpos kembali.
Satō Katsura

Jawaban:


10

Dengan GNU datamashdan GNU sort:

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

Ini berfungsi baik untuk data "cukup kecil". Mungkin atau mungkin tidak berfungsi dengan file Anda.

Sunting: Solusi di bawah ini tanpa transposisi harus kurang intensif sumber daya.


1
The rs perintah mungkin menjadi alternatif yang lebih ringan untuk datamashmisalnya rs -T < file_in.csv | sort | rs -T -C' '( rsharus tersedia sebagai paket pada sistem berbasis Debian)
steeldriver

2
FWIW, rs("membentuk kembali array data") tersedia di sistem dasar beberapa 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. Untuk baris pertama, kami secara numerik mengurutkannya menjadi 2 ... kolom terakhir menggunakan bagian numeriknya setelah digit Mterjadi di awal, menggunakan yang terkenal Schwartzian maneuver. Ini memberi kami indeks yang disusun ulang sehingga kolom keluar dalam urutan yang diurutkan secara numerik (M1, M2, M3, ...)
  2. Yang tersisa hanyalah menggunakan indeks-indeks ini yang berasal dari @I untuk mengatur kembali @Felemen - elemen.
  3. Menetapkan array dalam bentuk tanda kutip ganda mengubahnya menjadi string dengan elemen spasi terpisah.
  4. -ppilihan untuk Perl memungkinkan cetak otomatis $_isi, -lharus menambahkan newline.

6

Menggunakan modul perl Sort :: Wajar

memasukan data

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

keluaran

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 untuk yang paling elegan, tidak menganggap awalan yang terlalu spesifik untuk nama kolom, solusi satu pass.
arielf

4

Jika Anda telah menginstal rsutilitas , Anda dapat melakukan ini:

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

Atau semuanya dalam satu baris:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • Pertama rsTranspos input data (dengan bidang sparated space)
  • Grup perintah:
    • sedmembaca baris pertama, mengeluarkannya, lalu berhenti, meninggalkan sisa pipa rstidak tersentuh. stdbufdiperlukan untuk memastikan bahwa sedhanya membaca hingga baris baru pertama dan tidak lebih jauh, dengan mematikan buffering input
    • sortS baris yang tersisa
  • Yang kedua rsmengubah aliran yang dihasilkan kembali ke format aslinya.

rsdiinstal secara default di MacOS. Pada sistem Linux, Anda mungkin harus menginstalnya - mis

sudo apt install rs

Peringatan: stdbufdan sorts -Vpilihan yang GNU-spesifik sehingga tidak akan bekerja pada MacOS dimodifikasi.


0

Jika Anda memiliki GNU awk, Anda dapat mencoba ini:

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

Dengan 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

Saya tidak tahu apakah Anda menganggap ini sebagai jawaban yang baik, tapi ...

Mengapa Anda tidak menggunakan database untuk menyelesaikan masalah ini? Anda bisa mengimpor dataset Anda sebagai tabel sementara, dan kemudian melakukan a

PILIH kolom1, kolom2, ... kolom-n DARI my_temp_table

Anda dapat menggunakan filter lain, atau transformasi sesuai kebutuhan. Kemudian, Anda dapat memformat ulang output Anda sesuai kebutuhan.

Semua tugas ini dapat diprogram sebagai skrip bash, dan merantai output menggunakan pipa.

Terkadang saya telah menggunakan perintah "pv" untuk melihat progres output antar perintah.

Untuk mengimpor dataset Anda dapat memprogram ETL menggunakan Integrasi Data Pentaho.


0

Mungkin ini juga bisa membantu Anda.

  1. Pertama, Anda dapat menggunakan transpos file Anda (salah satunya /programming/1729824/an-fficiency-way-to-transpose-a-file-in-bash )
  2. Urutkan kolom pertama dengan perintah sortir.
  3. Transposis lagi.

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    
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.