Сохраните первые K полей фиксированными, но суммируйте остальные поля между двумя файлами.

Вопрос или проблема

Привет, у меня есть два файла с одинаковым числом столбцов и строк. Первые 8 столбцов идентичны.

файл1:

chr22   10550966    22:10550966:C:T C   T   .   .   .   0.95    0.99    0.99    0.67
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.05    0.01    0.01    0.33

файл2:

chr22   10550966    22:10550966:C:T C   T   .   .   .   0.97    0.59    0.97    0.88
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0.02    0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0.02    0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.02    0.02    0   0.11
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0.37    0   0.01

Как написать скрипт оболочки для выполнения поэлементного сложения между двумя файлами, начиная с 9-го поля до последнего столбца, чтобы получить результат, как в следующем примере:

chr22   10550966    22:10550966:C:T C   T   .   .   .   1.92    1.58    1.96    1.55
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0.02    0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0.02    0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.02    0.02    0   0.11
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.05    0.38    0.01    0.34

С помощью perl в режиме awk:

perl -lane '
  $_ = <STDIN>; @F2 = split;
  $F[$_] += $F2[$_] for 8 .. $#F;
  print join "\t", @F' файл1 < файл2

Здесь используется любое количество пробелов в качестве разделителя полей ввода (и игнорируются начальные и конечные пробелы) и TAB в качестве разделителя полей вывода. Для TAB как в качестве входного, так и выходного разделителя полей:

perl -F'\t' -lane '
  $_ = <STDIN>; chomp; @F2 = split "\t";
  $F[$_] += $F2[$_] for 8 .. $#F;
  print join "\t", @F' файл1 < файл2

Обратите внимание на 8 вместо 9, так как perl начинает нумерацию своих элементов массива с 0, а не с 1.

Эквивалент awk будет выглядеть так:

awk -F'\t' -v OFS='\t' '
  {
    getline l2 < "file2"; split(l2, f2)
    for (i = 9; i <= NF; i++) $i += f2[i]
    print
  }' файл1

Используя awk:

awk '
    BEGIN{OFS="\t"}
    NR==FNR{
        a[NR]["c09"]=$9
        a[NR]["c10"]=$10
        a[NR]["c11"]=$11
        next
    }
    {
        $9= a[FNR]["c09"] + $9
        $10=a[FNR]["c10"] + $10
        $11=a[FNR]["c11"] + $11
        print
    }
' файл1 файл2

chr22   10550966    22:10550966:C:T C   T   .   .   .   1.92    1.58    1.96    0.88
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0.02    0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0.02    0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.02    0.02    0   0.11
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.05    0.38    0.01    0.01

Позвольте awk прочитать два файла, размещенных рядом:

$ paste файл1 файл2 | awk '{ print $1, $2, $3, $4, $5, $6, $7, $8, $9+$17, $10+$18, $11+$19, $12+$20 }'
chr22 10550966 22:10550966:C:T C T . . . 0.95 0.99 0.99 0.67
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.01 0.01 0.33

Если ваш ввод разделен табуляцией и ваш вывод также должен быть таким, то задайте FS = OFS = "\t" в коде awk:

$ paste файл1 файл2 | awk 'BEGIN { FS=OFS="\t" } { print $1, $2, $3, $4, $5, $6, $7, $8, $9+$17, $10+$18, $11+$19, $12+$20 }'
chr22   10550966        22:10550966:C:T C       T       .       .       .       0.95    0.99    0.99 0.67
chr22   10550966        22:10550966:C:T C       T       .       .       .       0       0       0    0
chr22   10550966        22:10550966:C:T C       T       .       .       .       0       0       0    0
chr22   10550966        22:10550966:C:T C       T       .       .       .       0       0       0    0
chr22   10550966        22:10550966:C:T C       T       .       .       .       0.05    0.01    0.01 0.33

Ответ или решение

Для решения задачи суммирования значений полей в двух файлах, сохраняя первые 8 полей неизменными, можно воспользоваться командой awk или perl. Ниже представлены несколько примеров кода на этих языках.

Условия задачи

У нас есть два файла, file1 и file2, каждый из которых содержит одинаковое количество строк и одинаковое количество колонок. Первые 8 колонок в обоих файлах идентичны, а начиная с 9-й колонки содержатся числовые значения, которые требуется сложить между файлами. После выполнения операции суммирования, необходимо вывести результат в том же формате, что и исходные файлы.

Пример данных

file1:

chr22   10550966    22:10550966:C:T C   T   .   .   .   0.95    0.99    0.99    0.67
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.05    0.01    0.01    0.33

file2:

chr22   10550966    22:10550966:C:T C   T   .   .   .   0.97    0.59    0.97    0.88
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0.02    0   0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0   0.02    0
chr22   10550966    22:10550966:C:T C   T   .   .   .   0.02    0.02    0   0.11
chr22   10550966    22:10550966:C:T C   T   .   .   .   0   0.37    0   0.01

Пример реализации с помощью awk

awk -F'\t' -v OFS='\t' '
{
    getline l2 < "file2"; 
    split(l2, f2);
    for (i = 9; i <= NF; i++) 
        $i += f2[i - 8]; 
    print
}' file1

Объяснение кода

  • -F'\t' устанавливает разделителем полей символ табуляции.
  • -v OFS='\t' задаёт символ табуляции как разделитель в выходных данных.
  • getline l2 < "file2" считывает строку из файла file2.
  • split(l2, f2) разбивает считанную строку на массив f2.
  • Цикл for (i = 9; i <= NF; i++) проходит по всем полям, начиная с 9, и выполняет суммирование значений из обоих файлов.
  • print выводит результат на экран.

Пример реализации с помощью perl

perl -lane '
    $_ = <STDIN>; 
    chomp; 
    @F2 = split;
    for (my $i = 8; $i <= $#F; $i++) {
        $F[$i] += $F2[$i];
    }
    print join("\t", @F);
' file1 < file2

Объяснение кода

  • -lane позволяет обрабатывать строки файла в режиме, который разделяет их по пробелам и табуляциям.
  • $_ = <STDIN> считывает строку из стандартного ввода.
  • @F2 = split разбивает строку на массив.
  • Цикл for суммирует элементы массива.
  • print join("\t", @F) выводит итоговую строку в табличном формате.

Заключение

Эти решения дают возможность эффективно выполнять элементное сложение полей в двух файлах, сохраняя при этом первичную структуру данных. Использование awk или perl позволяет выбрать наиболее подходящий инструмент в зависимости от предпочтений разработчика.

Оцените материал
Добавить комментарий

Капча загружается...