Как отсортировать столбцы по первой строке?

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

Спасибо

LLVerardo
источник
Можете ли вы добавить пример с несколькими строками набора данных?
jcbermu
ваш ожидаемый результат отсортирован только по первой строке, остальные значения остались прежними, почему?
РоманПерехрест
На самом деле, это должно следовать за столбцами, была ошибка примера. извините
LLVerardo
Нужно отсортировать весь столбец по первой строке.
Л.Л.Верардо
2
Транспонировать, сортировать по первому столбцу, транспонировать обратно.
Satō

Ответы:

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.
Кусалананда
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 Sort :: Naturally

входные данные

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только чтение до первой новой строки и не дальше, отключив входную буферизацию
    • sortс оставшимися строками
  • Вторая 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)
whereswalden
источник
0

Я не знаю, считали ли вы это хорошим ответом, но ...

Почему вы не используете базу данных для решения этой проблемы? Вы можете импортировать ваш набор данных как временную таблицу, а затем сделать

SELECT column1, column2, ... column-n FROM 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    
Мустафа ДОГРУ
источник