Объединить данные файла, отсортировать по хромосоме, расположить рядом друг с другом - тиски столбца

Хотя lsblkпредставил /dev/sda3с размером 58,8 ГБ, это размер раздела, а не физического тома LVM. Таким образом, LVM не может видеть дополнительное пространство. Поскольку раздел имеет правильный размер, необходимо изменить размер двух вещей :: физического тома и корневого логического тома :

.
  1. pvresize /dev/sda3
  2. lvextend -l +100%FREE /dev/c1/root
3
09.11.2019, 15:53
5 ответов

Другой awkподход. Этот будет печатать NAдля случаев, когда конкретный вариант отсутствует в одном из входных файлов :

.
awk '{ if(FNR==1){files[fnum++]=FILENAME}else{var[$1"\t"$2][FILENAME]=$3}} END{ for(v in var){for(file in files){if(! var[v][files[file]]){var[v][files[file]]="NA"}}}printf "chr\tposition "; for(i=1;i<=fnum;i++){printf "value-samp%s\t",i;} print "";for(v in var){ printf "%s ",v; for(file in var[v]){if(file in var[v]); else{var[v][file]="NA";}  printf "%s\t", var[v][file] } print ""}}' s1 s2

Или, если вам не нравится вся эта краткость:

awk '{ 
        if(FNR==1){
            files[fnum++]=FILENAME
        }
        else{
            var[$1"\t"$2][FILENAME]=$3
        }
      } 
      END{ 
        for(v in var){
            for(file in files){
                if(! var[v][files[file]]){
                    var[v][files[file]]="NA"
                }
            }
        }
        printf "chr\tposition "; 
        for(i=1;i<=fnum;i++){
            printf "value-samp%s\t",i;
        } 
        print "";
        for(v in var){ 
            printf "%s ",v; 
            for(file in var[v]){
                if(file in var[v]); 
                else{
                    var[v][file]="NA";
                }
            printf "%s\t", var[v][file];
        } 
    print "";
    }
}' s1 s2

Измените s1и s2на фактические имена файлов, которые вы используете. Выполнение вышеуказанного на вашем примере ввода возвращает:

chr position value-samp1    value-samp2 
1   3774318 1   NA  
1   3775200 2   1   
1   3774319 1   NA  
1   3775201 7   1   
1   3775202 70  10  
1   3775203 7   1   
1   3775204 270 12  
1   3775205 3   1   
1   3775206 5   13  
1   3775207 NA  1   
1   3775208 NA  1   
1   3775209 NA  18  
2
27.01.2020, 21:24

Взяв это решение аналогичной проблемы за основу, нам нужно будет его тонко настроить, чтобы получить то, что вы хотите. Это не ответ, а просто набросок, и в нем используется какой-то псевдокод(sic? ), чтобы обрисовать в общих чертах, что должно быть сделано.

Обзор команды Linux join и ее возможностей необходим для успешного решения. Обратите внимание, что сортировка каждого входного файла по порядку в определенном поле (здесь с использованием номера хромосомы, поле 2 )перед объединением имеет важное значение.

Так как объединение может объединять только два файла, нам потребуется выполнить объединение несколько раз, поэтому потребуется определенная структура программирования и механизм управления. Нам также нужно будет изменить сами данные, так как вы указали пустые (нулевые )значения, которые следует заменить на 0.

1 )Скопируйте первый файл данных под другим именем, возможно, samp _0

2 )Проверьте каждую строку samp _0 на наличие значения поля 3. Если ноль, замените на 0.

3 )Инициализируйте значение x , чтобы оно соответствовало номеру файла данных.

4 )Создайте цикл for/next для последовательного использования каждого файла данных. Сколько файлов данных у вас есть? Ну, чтобы это работало без редактирования сценария каждый раз, когда вы его запускаете, запустите сценарий, пока не закончатся файлы данных с циклом for/next.

5 )Внутри цикла for/next сделайте две вещи.

5A )Проверить каждую строку следующего файла на наличие значения поля 3. Если ноль, заменить на 0.

5B )выполнить соединение включая непарные линии (с опцией-a )в поле номера хромосомы (2 )файла samp _0 и файл samp _x с автоматическим форматированием (с использованием опции-o auto ), поэтому он объединяет строки данных для всех хромосом, а не только те, у которых есть данные как в файле samp _0 , так и в файле samp _x . Запишите вывод в файл samp _0 .

6 )Если есть другой файл данных, увеличьте значение x , затем вернитесь и повторите 3 ). Если все файлы данных были объединены, выйдите из цикла for/next, потому что вы закончили.

0
27.01.2020, 21:24

Я проигнорировал chrна данный момент, потому что, если он всегда равен 1, его можно безопасно игнорировать, иначе ОП должен объяснить, как он вписывается.

awk 'BEGIN {printf "position " }
        FNR>1{ 
        if (FNR==2) {nof+=1; printf ("%s%s ","Sam", nof )};
        pos[$2]=$2; data[$2, nof]=$3}
    END { printf "\n"; for (p in pos) {printf ("%s ", pos[p]); 
        for (d=1;d<=nof;d++) printf ("%s ", data[p,d]+0); print "\n"}
    }' file1 file2 | column -t

Выход

position  Sam1  Sam2
3774318   1     0
3774319   1     0
3775200   2     1
3775201   7     1
3775202   70    10
3775203   7     1
3775204   270   12
3775205   3     1
3775206   5     13
3775207   0     1
3775208   0     1
3775209   0     18

Прохождение

Печатать заголовок первого столбца при запуске

awk 'BEGIN {printf "position " }

Игнорировать все первые строки как заголовки

FNR>1{ 

Во 2-й строке каждого файла увеличьте количество файлов и напечатайте заголовок

if (FNR==2) {nof+=1; printf ("%s%s ","Sam", nof )};

Для каждой строки после заголовка поместите позицию в массив pos; установить другой массив data, содержащий значение sam, проиндексированное posи номер файла (выборки )

pos[$2]=$2; data[$2, nof]=$3}

После считывания всех файлов напечатайте newlineв заголовках, затем повторите posпечать каждой позиции

END { printf "\n"; for (p in pos ) {printf ("%s ", pos[p]); 

Затем выполните итерацию по индексу массива dataпо номерам pи sam/file, добавляя 0 к любым нулевым значениям data, чтобы что-то печаталось даже при отсутствии данных; затем напечатайтеnewline

for (d=1;d<=nof;d++) printf ("%s ", data[p,d]+0); print "\n"}

Только входные файлы и вывод вывода через column, чтобы он выглядел красиво

}' file1 file2 | column -t

Добавлен chr в предположении, что это другой индекс

awk 'BEGIN {printf "chr position " }
        FNR>1{
        if (FNR==2) {nof+=1; printf ("%s%s ","Sam", nof )};
        chr[$1]=$1; pos[$2]=$2; data[$1, $2, nof]=$3}
    END { printf "\n"; for (c in chr) {for (p in pos ) {printf ("%s %s ", chr[c], pos[p]); 
        for (d=1;d<=nof;d++) printf ("%s ", data[c, p, d]+0); print "\n"}
    }}' file1 file2 | column -t
0
27.01.2020, 21:24

Я использую другой подход, больше в стиле SQL, если можно так сказать. У меня есть только основная идея и некоторые детали. Идея состоит в том, чтобы использовать «нормализованный» список, т.е. сначала добавить идентификатор источника -в одну большую общую таблицу :

.

У меня есть образцы файлов с ch.s1по ch.sn; Я беру «chr» и «pos» в качестве первичного ключа.

. chr.sh >ch.tmp

for f in ch.s?
do 
  cat $f | while read l  
  do 
    echo "$l $f"
  done
done 

Итак, теперь это один большой файл с 4-м столбцом, исходный (файл ). Для простоты я использовал временный файл.

Отсюда идет «тройник»:

Чтобы получить список источников для коммун, вы можете сделать:

]# grep -o "ch.s.*" ch.tmp | sort | uniq -c
      3 ch.s1
      4 ch.s2
      2 ch.s3

(-cмогут дать ценную информацию; Я использую grep -o, потому что я напутал с разделителями(cutсчитает каждый пробел?? )). Это всего лишь один из способов получить этот список, но напрямую из данных. Это инвестиции.

Этот отсортированный список является заголовком и может использоваться для заполнения таблицы.

И подготовить отчет о том большом столе:

]# sort ch.tmp -k1,2 -k4 
1  16     A ch.s1
1  256    B ch.s1
1  333   dD ch.s2
1  4096   A ch.s1
1  4096  DD ch.s2
1  4096   A ch.s3
2  333   Dd ch.s2
2  777    x ch.s2
3 6666    F ch.s3

Эта сортировка является единственной большой операцией. -Я рассчитываю на ее эффективность во всех ситуациях.

После этих двух приготовлений остается немного зацикливания, но только очень "локально" :для каждой строки данных вы только перебираете в цикле фиксированное количество столбцов, ставя "значение" или "ноль".

Если вы возьмете эту часть:

1  4096   A ch.s1
1  4096  DD ch.s2
1  4096   A ch.s3

...это показывает, как строки готовы к печати одна за другой, почти. Нет необходимости в полном поиске (цикла -в -цикле -).

С элегантным способом «тройника» отch.tmp(унифицированной таблицы )к «группе по источнику», т.е. grep -oи sort -k..., этот подход должен быть готов также для «больших» данных. Тем более, что шаги можно регулировать.

Он имитирует чтение в таблицу SQL, а также отчетную часть в виде сводной таблицы.


Каков реалистичный сценарий сравнительного анализа?

20 файлов примеров по 50 КБ каждый,с небольшим перекрытием, как в ОП?

С Perl, а также с awk, я думаю, вы можете сделать этот подход очень легко. Со сценарием bash я не знаю, из-за производительности массива; с bash вы можете использовать файл tmp, как в моем плане.

0
27.01.2020, 21:24

С помощью Миллера(https://github.com/johnkerl/miller)вы можете запустить

mlr --c2p --ifs ' '  --repifs \
sort -f chr,position,value \
then nest --implode --values --across-records -f value \
then nest --explode --across-fields --values -f value \
then unsparsify then clean-whitespace input0*.csv >output.csv

И получить

chr position value_1 value_2
1   3774318  1       -
1   3774319  1       -
1   3775200  1       2
1   3775201  1       7
1   3775202  10      70
1   3775203  1       7
1   3775204  12      270
1   3775205  1       3
1   3775206  13      5
1   3775207  1       -
1   3775208  1       -
1   3775209  18      -

Примечание:

  • вы должны адаптировать команду к именам ваших входных файлов. В моем примере я использовалinput0*.csv
  • , если вы хотите получить настоящий CSV-файл, измените --c2pна --csv.
0
27.01.2020, 21:24

Теги

Похожие вопросы