Làm thế nào để sắp xếp các cột dựa trên dòng đầu tiên?


12

Tôi cần sắp xếp các cột của một tập dữ liệu rất lớn (1000 dòng và 700000 cột). Ví dụ, các cột của tôi được sắp xếp ngẫu nhiên như: col1 col4 col3 col2 và tôi cần sắp xếp nó.

Tôi đã thử một số lệnh, nhưng không thành công.

thí dụ:

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

Trong ví dụ này, dấu chấm có nghĩa là tôi có rất nhiều cột và dòng. Một lần nữa, tôi cần sắp xếp các cột để giống như:

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

Cảm ơn bạn


Bạn có thể thêm một ví dụ với một vài dòng của tập dữ liệu không?
jcbermu

kết quả mong đợi của bạn chỉ có dòng đầu tiên được sắp xếp, các giá trị khác vẫn giữ nguyên, tại sao?
RomanPerekhrest

Trên thực tế, nó cần phải theo các cột, là một sai lầm của ví dụ. xin lỗi
LLVerardo

Cần toàn bộ cột được sắp xếp dựa trên dòng đầu tiên.
LLVerardo

2
Chuyển vị, sắp xếp theo cột đầu tiên, chuyển trở lại.
Satō Katsura

Câu trả lời:


10

Với GNU datamashvà GNU sort:

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

Điều này hoạt động tốt cho dữ liệu "hợp lý nhỏ". Nó có thể hoặc không thể làm việc với tập tin của bạn.

Chỉnh sửa: Các giải pháp bên dưới không có chuyển vị sẽ ít tốn tài nguyên hơn.


1
Lệnh rs có thể là một thay thế nhẹ hơn cho datamashví dụ rs -T < file_in.csv | sort | rs -T -C' '( rsnên có sẵn dưới dạng gói trên các hệ thống dựa trên Debian)
Steeldo

2
FWIW, rs("định hình lại một mảng dữ liệu") có sẵn trong các hệ thống cơ sở của một số 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. Đối với dòng đầu tiên, chúng tôi sắp xếp số thứ hai ... cột cuối cùng bằng cách sử dụng các phần số của chúng sau khi chữ số Mxuất hiện ở đầu, sử dụng số được biết đến Schwartzian maneuver. Điều này cho chúng ta các chỉ số được sắp xếp lại để các cột xuất hiện theo thứ tự được sắp xếp theo số (M1, M2, M3, ...)
  2. Tất cả những gì còn lại là sử dụng các chỉ số đến từ @Iđể sắp xếp lại các @Fyếu tố.
  3. Việc chỉ định mảng ở dạng trích dẫn kép sẽ chuyển nó thành một chuỗi với các phần tử được phân tách.
  4. -ptùy chọn để Perl cho phép tự động in $_nội dung, -lsẽ thêm newline.

6

Sử dụng mô-đun perl Sắp xếp :: Đương nhiên

dữ liệu đầu vào

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

đầu ra

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 cho thanh lịch nhất, không giả sử tiền tố quá cụ thể cho tên cột, giải pháp vượt qua.
thân

4

Nếu bạn đã cài đặt rstiện ích , bạn có thể làm điều này:

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

Hoặc tất cả trên một dòng:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • Đầu tiên rschuyển đổi dữ liệu đầu vào (với các trường có khoảng cách không gian)
  • Nhóm lệnh:
    • sedđọc dòng đầu tiên, xuất nó, sau đó thoát ra, để phần còn lại của ống rskhông bị ảnh hưởng. stdbufđược yêu cầu để đảm bảo rằng sedchỉ đọc tối đa dòng mới đầu tiên và không tiếp tục, bằng cách tắt bộ đệm đầu vào
    • sorts các dòng còn lại
  • Cái thứ hai rschuyển luồng kết quả trở lại định dạng ban đầu của nó.

rsđược cài đặt theo mặc định trên MacOS. Trên các hệ thống Linux, bạn có thể phải cài đặt nó - vd

sudo apt install rs

Hãy cẩn thận: stdbufvà tùy chọn sorts -Vlà dành riêng cho GNU nên sẽ không hoạt động trên MacOS chưa sửa đổi.


0

Nếu bạn có GNU awk, bạn có thể thử điều này:

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

Trong 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

Tôi không biết nếu bạn coi đây là một câu trả lời hay, nhưng ...

Tại sao bạn không sử dụng cơ sở dữ liệu để giải quyết vấn đề này? bạn có thể nhập tập dữ liệu của mình dưới dạng bảng tạm thời và sau đó thực hiện

CHỌN cột1, cột2, ... cột-n TỪ my_temp_table

Bạn có thể sử dụng các bộ lọc hoặc chuyển đổi khác khi bạn cần. Sau đó, bạn có thể định dạng lại đầu ra của bạn khi bạn cần.

Tất cả các tác vụ này có thể được lập trình dưới dạng tập lệnh bash và tạo chuỗi đầu ra bằng các đường ống.

Đôi khi tôi đã được sử dụng lệnh "pv" để xem tiến trình đầu ra giữa các lệnh.

Để nhập tập dữ liệu, bạn có thể lập trình một ETL bằng cách sử dụng Pentaho Data Integration.


0

Có lẽ điều này cũng có thể giúp bạn.

  1. Trước tiên, bạn có thể sử dụng chuyển đổi tệp của mình (một trong /programming/1729824/an-ffic-way-to-transpose-a-file-in-bash )
  2. Sắp xếp cột đầu tiên với lệnh sort.
  3. Chuyển tiếp một lần nữa.

Ví dụ:

$ 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    
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.