Як сортувати стовпчики на основі першого рядка?


12

Мені потрібно сортувати стовпці дуже великого набору даних (1000 рядків і 700000 стовпців). Наприклад, мої стовпці розташовані випадковим чином: col1 col4 col3 col2, і мені потрібно сортувати це.

Я пробував кілька команд, але успіху не було.

приклад:

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

У цьому прикладі крапки означають, що у мене багато стовпців і рядків. Знову мені потрібно сортувати стовпчики так:

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

Дякую


Чи можете ви додати приклад з кількома рядками набору даних?
jcbermu

ваш очікуваний результат відсортований лише у першому рядку, інші значення залишаються незмінними, чому?
RomanPerekhrest

Власне, їй потрібно стежити за стовпчиками, була помилковим прикладом. вибачте
LLVerardo

Потрібно сортувати весь стовпчик на основі першого рядка.
LLVerardo

2
Перемістити, сортувати за першим стовпцем, перемістити назад.
Satō Katsura

Відповіді:


10

З GNU datamashта GNU sort:

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

Це чудово працює для "досить невеликих" даних. Він може не працювати з вашим файлом.

Редагувати: рішення, наведені нижче, без транспозицій, повинні бути менш ресурсомісткими.


1
Команда rs може бути легшою альтернативою, datamashнаприклад rs -T < file_in.csv | sort | rs -T -C' '( rsмає бути доступна як пакет у системах на базі Debian)
steeldriver

2
FWIW, rs("переробити масив даних") доступний в базових системах деяких 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. Для першого рядка ми чисельно сортуємо це 2-й ... останній стовпці, використовуючи їх числові частини після цифри, Mщо виникає на початку, використовуючи добре відомий Schwartzian maneuver. Це дає нам індекси, упорядковані таким чином, що стовпці виходять у цифровому порядку (M1, M2, M3, ...)
  2. Залишилося лише скористатись цими індексами, що надходять @Iдля переупорядкування @Fелементів.
  3. Призначення масиву у формі з подвійним котируванням перетворює його в рядок з розділеним простором елементів.
  4. -pопція Perl дозволяє автодрук $_вмісту, слід -lдодати newline.

6

Використання модуля perl Сортувати :: Природно

вхідні дані

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

вихід

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 для найбільш елегантних, не передбачає занадто специфічного префікса для імен стовпців, рішення з одним проходом.
аріельф

4

Якщо у вас встановлена rsутиліта , ви можете це зробити:

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

Або все в одному рядку:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • Перший rsпереміщує вхідні дані (з полями, розділеними простором)
  • Командна група:
    • sedчитає перший рядок, виводить його, а потім виходить, залишаючи решту труби rsнедоторканою. stdbufПотрібно гарантувати, що sedчитає лише до першого нового рядка і не далі, вимикаючи буферне введення
    • sorts решта рядків
  • Другий rsпереміщує отриманий потік назад у початковий формат.

rsвстановлено за замовчуванням на MacOS. У системах Linux, можливо, доведеться його встановити - наприклад

sudo apt install rs

Параметр Caveat: stdbufі sorts -Vє специфічними для GNU, тому не працюватиме на незміненому MacOS.


0

Якщо у вас є GNU awk, ви можете спробувати це:

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

На 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

Я не знаю, чи вважали ви це доброю відповіддю, але ...

Чому ви не використовуєте базу даних для вирішення цієї проблеми? ви можете імпортувати свій набір даних у вигляді тимчасової таблиці, а потім виконати

ВИБІР колонку1, стовпчик2, ... стовпець-п ВІД my_temp_table

Ви можете використовувати інші фільтри або перетворення, як вам потрібно. Тоді ви можете переформатувати результат, як вам потрібно.

Усі ці завдання можна запрограмувати як сценарій bash та ланцюжок виходів за допомогою труб.

Іноді я використовував команду "pv", щоб побачити хід виходу між командами.

Для імпорту набору даних ви можете запрограмувати ETL за допомогою інтеграції даних Pentaho.


0

Можливо, це теж може вам допомогти.

  1. Спочатку ви можете використати перенести свій файл (один із /programming/1729824/an-efficient-way-to-transpose-a-file-in-bash )
  2. Сортувати перший стовпець за допомогою команди сортування.
  3. Перекладіть знову.

Наприклад:

$ 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    
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.