Использование регулярных выражений для умножения и суммирования числовых c строковых символов, содержащихся в ха sh смешанных числовых c строк - PullRequest
0 голосов
/ 03 марта 2020

Не слишком вдаваясь в биологию, белки сделаны из аминокислот. Каждая из 20 аминокислот, из которых состоят белки, представлена ​​символами в последовательности. Каждый аминокислотный символ имеет свою химическую формулу, которую я представляю как строки. Например, "M" имеет формулу "C5H11NO2S"

. Учитывая 20 различных формул (и разную частоту каждой аминокислоты в последовательности белка), я хочу собрать все 20 из них в одну формула, которая даст общую формулу для белка.

Итак, во-первых: умножьте каждую формулу на частоту ее символа в последовательности

Во-вторых: сложите все умноженные формулы в одну формулу.

Для этого sh я сначала попытался умножить частоту каждой аминокислоты в последовательности на числа в химической формуле. Я сделал это, используя .tally

sequence ="MGAAARTLRLALGLLLLATLLRPADACSCSPVHPQQAFCNADVVIRAKAVSEKEVDSGNDIYGNPIKRIQYEIKQIKMFKGPEKDIEFI"
sequence.chars.string.tally --> {"M"=>2, "G"=>5, "A"=>11, "R"=>5, "T"=>2, "L"=>9, "P"=>5, "D"=>5, "C"=>3, "S"=>4, "V"=>5, "H"=>1, "Q"=>4, "F"=>3, "N"=>3, "I"=>8, "K"=>7, "E"=>5, "Y"=>2}

Затем я перечислил все символы и формулы аминокислот в га sh

hash_of_formulas = {"A"=>"C3H7NO2", "R"=>"C6H14N4O2", "N"=>"C4H8N2O3", "D"=>"C4H7NO4", "C"=>"C3H7NO2S", "E"=>"C5H9NO4", "Q"=>"C5H10N2O3", "G"=>"C2H5NO2", "H"=>"C6H9N3O2", "I"=>"C6H13NO2", "L"=>"C6H13NO2", "K"=>"C6H14N2O2", "M"=>"C5H11NO2S", "F"=>"C9H11NO2", "P"=>"C5H9NO2", "S"=>"C3H7NO3", "T"=>"C4H9NO3", "W"=>"C11H12N2O2", "Y"=>"C9H11NO3", "V"=>"C5H11NO2"}

Пример процесса для моей общей цели: в sequence, "M" происходит дважды, поэтому "C5H11NO2S" станет "C10H22N2O4S2". "C" имеет формулу "C3H7NO2S" происходит 3 раза: в sequence так "C3H7NO2S" становится "C9H21N3O6S3"

Итак, суммирование "C10H22N2O4S2" и "C9H21N3O6S3" даст "C19H43N5O10S5"

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

formula_multiplied_by_frequency = "C5H11NO2S".gsub(/\d+/) { |x| x.to_i * 4}

Но я не уверен ни в каком методе использования регулярного выражения для строк, встроенных в хэши

Ответы [ 2 ]

1 голос
/ 03 марта 2020

Если я правильно понимаю, вы хотите предоставить общую формулу для данной последовательности белка. Вот как я это сделаю:

NUCLEOTIDES = {"A"=>"C3H7NO2", "R"=>"C6H14N4O2", "N"=>"C4H8N2O3", "D"=>"C4H7NO4", "C"=>"C3H7NO2S", "E"=>"C5H9NO4", "Q"=>"C5H10N2O3", "G"=>"C2H5NO2", "H"=>"C6H9N3O2", "I"=>"C6H13NO2", "L"=>"C6H13NO2", "K"=>"C6H14N2O2", "M"=>"C5H11NO2S", "F"=>"C9H11NO2", "P"=>"C5H9NO2", "S"=>"C3H7NO3", "T"=>"C4H9NO3", "W"=>"C11H12N2O2", "Y"=>"C9H11NO3", "V"=>"C5H11NO2"}
NUCLEOTIDE_COMPOSITIONS = NUCLEOTIDES.each_with_object({}) { |(nucleotide, formula), compositions|
  compositions[nucleotide] = formula.scan(/([A-Z][a-z]*)(\d*)/).map { |element, count| [element, count.empty? ? 1 : count.to_i] }.to_h
}

def formula(sequence)
  sequence.each_char.with_object(Hash.new(0)) { |nucleotide, final_counts|
    NUCLEOTIDE_COMPOSITIONS[nucleotide].each { |element, element_count|
      final_counts[element] += element_count
    }
  }.map { |element, element_count|
    "#{element}#{element_count.zero? ? "" : element_count}"
  }.join
end

sequence = "MGAAARTLRLALGLLLLATLLRPADACSCSPVHPQQAFCNADVVIRAKAVSEKEVDSGNDIYGNPIKRIQYEIKQIKMFKGPEKDIEFI"
p formula(sequence)
# => "C434H888N51O213S"

Вы не можете использовать регулярное выражение для умножения. Вы можете использовать его для разбора формулы, но тогда это зависит от вас и Ruby, чтобы сделать математику. Первая задача - подготовить поиск по составу, разбив каждую нуклеотидную формулу. Как только у нас есть состав ha sh для каждого нуклеотида, мы можем перебрать нуклеотидную последовательность и сложить все элементы каждого нуклеотида.

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

EDIT: Я, вероятно, сделал регулярное выражение немного более сложным, чем нужно, но он должен правильно разбирать такие вещи, как CuSO4. Я не знаю, является ли это случайностью или нет, что все нуклеотиды состоят только из элементов с односимвольным символом ...: P)

1 голос
/ 03 марта 2020

Givens

Нам дана строка, представляющая белок, состоящий из аминокислот:

sequence = "MGAAARTLRLALGLLLLATLLRPADACSCSPVHPQQAFCNADVVIR" + 
           "AKAVSEKEVDSGNDIYGNPIKRIQYEIKQIKMFKGPEKDIEFI"

и га sh, который содержит формулы амино кислоты:

formulas = {
  "A"=>"C3H7NO2", "R"=>"C6H14N4O2", "N"=>"C4H8N2O3", "D"=>"C4H7NO4", 
  "C"=>"C3H7NO2S", "E"=>"C5H9NO4", "Q"=>"C5H10N2O3", "G"=>"C2H5NO2", 
  "H"=>"C6H9N3O2", "I"=>"C6H13NO2", "L"=>"C6H13NO2", "K"=>"C6H14N2O2", 
  "M"=>"C5H11NO2S", "F"=>"C9H11NO2", "P"=>"C5H9NO2", "S"=>"C3H7NO3", 
  "T"=>"C4H9NO3", "W"=>"C11H12N2O2", "Y"=>"C9H11NO3", "V"=>"C5H11NO2"
}

Получение количества атомов в каждой аминокислоте

В качестве первого шага мы можем вычислить числа каждого атома в каждой аминокислоте:

counts = formulas.transform_values do |s|
  s.scan(/[CHNOS]\d*/).
    each_with_object({}) do |s,h|
    h[s[0]] = s.size == 1 ? 1 : s[1..-1].to_i
  end
end
  #=> {"A"=>{"C"=>3, "H"=>7,  "N"=>1, "O"=>2},
  #    "R"=>{"C"=>6, "H"=>14, "N"=>4, "O"=>2},
  #    ...
  #    "M"=>{"C"=>5, "H"=>11, "N"=>1, "O"=>2, "S"=>1} 
  #    ...
  #    "V"=>{"C"=>5, "H"=>11, "N"=>1, "O"=>2}} 

Вычислить формулу для белка

Тогда это просто:

def protein_formula(sequence, counts)
  sequence.each_char.
           with_object("C"=>0, "H"=>0, "N"=>0, "O"=>0, "S"=>0) do |c,h|
    counts[c].each { |aa,cnt| h[aa] += cnt }
  end.each_with_object('') { |(aa,nbr),s| s << "#{aa}#{nbr}" }
end

protein_formula(sequence, counts)
  #=> "C434H888N120O213S5"

Другой пример:

protein_formula("MCMPCFTTDHQMARKCDDCCGGKGRGKCYGPQCLCR", count)
  #=> "C158H326N52O83S11"

Объяснение расчета counts

Этот расчет:

counts = formulas.transform_values do |s|
  s.scan(/[CHNOS]\d*/).each_with_object({}) do |s,h|
    h[s[0]] = s.size == 1 ? 1 : s[1..-1].to_i
  end
end

использует метод Hash # transform_values ​​. Он вернет ha sh, имеющий те же ключи, что и ha sh formulas, со значениями этих ключей в formula, измененными блоком transform_values. Например, formulas["A"] ("C3H7NO2") «преобразуется» в га sh {"C"=>3, "H"=>7, "N"=>1, "O"=>2} в га sh, которое возвращается, counts.

transform_values передает каждое значение formulas для блока и устанавливает переменную блока, равную ему. Первое переданное значение - "C3H7NO2", поэтому оно устанавливает:

s = "C3H7NO2" 

Мы можем написать вычисление блока более просто:

h = {}
s.scan(/[CHNOS]\d*/).each do |s|
  h[s[0]] = s.size == 1 ? 1 : s[1..-1].to_i
end
h

(Как только вы поймете это вычисление, которое я объясняю ниже см. Enumerable # each_with_object , чтобы понять, почему я использовал этот метод в своем решении.)

После инициализации h пустым ха sh выполняются следующие вычисления:

h = {}
a = s.scan(/[CHNOS]\d*/)
  #=> ["C3", "H7", "N", "O2"] 

a вычисляется с использованием String # scan с регулярным выражением /[CHNOS]\d*/. Это регулярное выражение, или regex , соответствует ровно одному символу в классе символов [CHNOS], за которым следует ноль более (*) цифр (\d). Поэтому он разделяет строку "C3H7NO2" на подстроки, которые возвращаются в массиве, показанном при вычислении a выше. Продолжая,

a.each do |s|
  h[s[0]] = s.size == 1 ? 1 : s[1..-1].to_i
end

изменяет h на следующее:

h #=> {"C"=>3, "H"=>7, "N"=>1, "O"=>2} 

Переменная блока s первоначально устанавливается равной первому элементу a, который передается в Блок each:

s = "C3"

затем мы вычисляем:

h[s[0]] = s.size == 1 ? 1 : s[1..-1].to_i
 h["A"] = 2 == 1 ? 1 : "3".to_i
        = false ? 1 : 3
        3

Это повторяется для каждого элемента a.

Восклицательный знак построения формулы для белка

Мы можем упростить следующий код 1 :

sequence.each_char.with_object("C"=>0, "H"=>0, "N"=>0, "O"=>0) do |c,h|
  counts[c].each { |aa,cnt| h[aa] += cnt }
end.each_with_object('') { |(aa,nbr),s| s << "#{aa}#{nbr}" }

до более или менее следующего:

h = { "C"=>0, "H"=>0, "N"=>0, "O"=>0, "S"=>0 }
ch = sequence.chars
  #=> ["M", "G", "A",..., "F", "I"] 
ch.each do |c|
  counts[c].each { |aa,cnt| h[aa] += cnt }
end
h #=> {"C"=>434, "H"=>888, "N"=>120, "O"=>213, "S"=>5}

Когда первое значение ch ("M") передается в блок each (когда h = { "C"=>0, "H"=>0, "N"=>0, "O"=>0, "S"=>0 }), выполняются следующие вычисления:

c = "M"
g = counts[c]
  #=> {"C"=>10, "H"=>22, "N"=>2, "O"=>4, "S"=>1}  
g.each { |aa,cnt| h[aa] += cnt }
h #=> {"C"=>10, "H"=>22, "N"=>2, "O"=>4, "S"=>1} 

Наконец , (когда h #=> {"C"=>434, "H"=>888, "N"=>120, "O"=>213, "S"=>5})

s = ''
h.each { |aa,nbr| s << "#{aa}#{nbr}" }
s #=> "C434H888N120O213S5"

Когда aa = "C" и nbr = 434,

"#{aa}#{nbr}"
  #=> "C434"

добавлены к строке s.

1. (("C"=>0, "H"=>0, "N"=>0, "O"=>0) сокращенно для ({"C"=>0, "H"=>0, "N"=>0, "O"=>0}).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...