Обработка хромосомных данных в рубине - PullRequest
2 голосов
/ 04 января 2011

Скажем, у меня есть файл хромосомных данных, которые я обрабатываю с помощью Ruby,

#Base_ID    Segment_ID      Read_Depth  
1                           100            
2                           800         
3           seg1            1900            
4           seg1            2700           
5                           1600            
6                           2400            
7                           200
8                           15000
9           seg2            300
10          seg2            400
11          seg2            900
12                          1000
13                          600
... 

Я вставляю каждую строку в хэш массивов, мои ключи взяты из столбца 2, Segment_ID, а мои значения из столбца 3, Read_Depth, дают мне

mr_hashy = { 
  "seg1"  => [1900, 2700],
  ""      => [100, 800, 1600, 2400, 200, 15000, 1000, 600],
  "seg2"  => [300, 400, 900],
}

A primer , который представляет собой небольшой сегмент, состоящий из двух последовательных строк в приведенных выше данных, добавляется и следует за каждым регулярным сегментом. Обычные сегменты имеют значение непустой строки для Segment_ID и различаются по длине, в то время как строки с пустой строкой во втором столбце являются частями праймеров. Сегменты праймера всегда имеют одинаковую длину, 2. Приведенные выше значения Base_ID 1, 2, 5, 6, 7, 8, 12, 13 являются частями праймеров. Всего в приведенных выше данных представлено четыре сегмента праймеров.

Что я хотел бы сделать, так это встретить строку с пустой строкой в ​​столбце 2, Segment_ID, добавить READ_DEPTH к соответствующему элементу в моем хэше. Например, мой желаемый результат сверху будет выглядеть как

mr_hashy = {
  "seg1"   => [100, 800, 1900, 2700, 1600, 2400],
  "seg2"   => [200, 15000, 300, 400, 900, 1000, 600],
}

Ответы [ 3 ]

3 голосов
/ 04 января 2011
hash = Hash.new{|h,k| h[k]=[] }

# Throw away the first (header) row
rows = DATA.read.scan(/.+/)[1..-1].map do |row|
  # Throw away the first (entire row) match
  row.match(/(\d+)\s+(\w+)?\s+(\d+)/).to_a[1..-1]
end

last_segment       = nil
last_valid_segment = nil
rows.each do |base,segment,depth|
  if segment && !last_segment
    # Put the last two values onto the front of this segment
    hash[segment].unshift( *hash[nil][-2..-1] )
    # Put the first two values onto the end of the last segment
    hash[last_valid_segment].concat(hash[nil][0,2]) if last_valid_segment
    hash[nil] = []
  end
  hash[segment] << depth
  last_segment = segment
  last_valid_segment = segment if segment
end
# Put the first two values onto the end of the last segment
hash[last_valid_segment].concat(hash[nil][0,2]) if last_valid_segment
hash.delete(nil)

require 'pp'
pp hash
#=> {"seg1"=>["100", "800", "1900", "2700", "1600", "2400"],
#=>  "seg2"=>["200", "15000", "300", "400", "900", "1000", "600"]}

__END__
#Base_ID    Segment_ID      Read_Depth  
1                           100            
2                           800         
3           seg1            1900            
4           seg1            2700           
5                           1600            
6                           2400            
7                           200
8                           15000
9           seg2            300
10          seg2            400
11          seg2            900
12                          1000
13                          600
2 голосов
/ 04 января 2011

Рефактор вторичной переработки. Я думаю, что это чисто, элегантно, и больше всего завершено. Это легко читать без жестко закодированных длин полей или безобразного RegEx. Я голосую за лучшего! Ура! Я лучший, ура! ;)

def parse_chromo(file_name)

  last_segment = ""
  segments = Hash.new {|segments, key| segments[key] = []}

  IO.foreach(file_name) do |line|
    next if !line || line[0] == "#"

    values = line.split
    if values.length == 3 && last_segment != (segment_id = values[1])
      segments[segment_id] += segments[last_segment].pop(2)
      last_segment = segment_id
    end

    segments[last_segment] << values.last
  end

  segments.delete("")
  segments
end

puts parse_chromo("./chromo.data")

Я использовал это в качестве файла данных:

#Base_ID    Segment_ID      Read_Depth  
1                           101            
2                           102            
3           seg1            103            
4           seg1            104           
5                           105            
6                           106            
7                           201
8                           202
9           seg2            203
10          seg2            204            
11                          205            
12                          206
13                          207
14                          208            
15                          209            
16                          210
17                          211
18                          212
19                          301
20                          302
21         seg3             303
21         seg3             304
21                          305
21                          306
21                          307

Какие выходы:

{
  "seg1"=>["101", "102", "103", "104", "105", "106"], 
  "seg2"=>["201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212"], 
  "seg3"=>["301", "302", "303", "304", "305", "306", "307"]
}
1 голос
/ 04 января 2011

Вот некоторый код на Ruby (хороший пример практики: P).Я предполагаю, что столбцы фиксированной ширины, как представляется, в случае с вашими входными данными.Код отслеживает, какие значения глубины являются значениями праймера, пока не найдет 4 из них, после чего он узнает идентификатор сегмента.

require 'pp'
mr_hashy = {}
primer_segment = nil
primer_values = []
while true
  line = gets
  if not line
    break
  end
  base, segment, depth = line[0..11].rstrip, line[12..27].rstrip, line[28..-1].rstrip
  primer_values.push(depth)
  if segment.chomp == ''
    if primer_values.length == 6
      for value in primer_values
        (mr_hashy[primer_segment] ||= []).push(value)
      end
      primer_values = []
      primer_segment = nil
    end
  else
    primer_segment = segment
  end
end
PP::pp(mr_hashy)

Вывод на входе обеспечен:

{"seg1"=>["100", "800", "1900", "2700", "1600", "2400"],
 "seg2"=>["200", "15000", "300", "400", "900", "1000"]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...