2011-01-03 5 views
2

sagen, dass ich eine Datei von chromosomalen Daten habe ich mit Ruby-bin VerarbeitungVerarbeitung chromosomale Daten in 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 
... 

ich jede Zeile in einen Hash von Arrays kleben, mit meinem Schlüssel aus der Spalte 2 genommen, Segment_ID, und meine Werte von Spalte 3, Read_Depth, gibt mir

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

a Primer, der ein kleines Segment, das in den oben genannten Daten, wird vorangestellt von zwei aufeinander folgenden Reihen besteht und folgt ea ch reguläres Segment. Reguläre Segmente haben einen nicht leeren String-Wert für Segment_ID und variieren in der Länge, während Zeilen mit einem leeren String in der zweiten Spalte Teile von Primern sind. Primer Segmente immer haben die gleiche Länge, 2. Oben gesehen, Base_ID 1, 2, 5, 6, 7, 8, 12, 13 sind Teile von Primern. Insgesamt sind in den obigen Daten vier Primersegmente vorhanden.

Was ich tun möchte, ist, wenn Sie eine Zeile mit einer leeren Zeichenfolge in Spalte 2, Segment_ID, die READ_DEPTH zu dem entsprechenden Element in meinem Hash hinzufügen. Zum Beispiel würde mein gewünschtes Ergebnis von oben so aussehen:

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

Es wäre hilfreich, wenn Sie weitere Beispieldaten mit mehreren Segmenten hinzugefügt genau sehen, was du meinst. So wie es ist, bin ich nicht sicher, wenn du Base sagst, meinst du jede Base ID oder wenn du eine Gruppe von Base IDs meinst oder klar ist, was du mit "zwei Zeilen von den obigen Daten" meinst, wie in Zeile 6 die "zwei Zeilen aus den obigen Daten "wären anders als das, was sie für Zeile 5 sind. Machen Sie auch die Lese-Tiefen alle verschiedenen Zahlen, so dass es klar ist, wohin sie gehen. –

+0

OK, also enthält ein Primer die zwei Zeilen über der ersten Zeile mit einer segment_ID. So können Sie herausfinden, wenn Sie analysieren oder es herausfinden, die base_id verwendend. Lass mich sehen, was ich wirklich schnell schreiben kann. –

+0

Gibt es eine Idee, warum die Datenquelle Primer, die zu einem bestimmten Segment gehören, vor der ersten Segment_ID platziert und nicht einfach danach? –

Antwort

3
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 
1

Hier ist ein Ruby-Code (schönes Praxisbeispiel: P). Ich gehe von Spalten mit fester Breite aus, was bei Ihren Eingabedaten der Fall zu sein scheint. Der Code verfolgt, welche Tiefenwerte Grundwerte sind, bis er 4 von ihnen findet, wonach er die Segment-ID kennt.

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) 

Ausgabe am Eingang zur Verfügung gestellt:

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

@Phorgz Danke für die Identifizierung Ich hatte ein Problem, obwohl das nicht das richtige war. Ich habe die Frage falsch gelesen, aber jetzt ist sie behoben! – marcog

2

Second-ish refactor. Ich denke, das ist sauber, elegant und vor allem komplett. Es ist leicht zu lesen, ohne fest codierte Feldlängen oder hässliche RegEx. Ich stimme mir als das Beste! Yay! Ich bin der Beste, yay! ;)

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") 

habe ich dies als meine Datendatei:

#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 

Welche Ausgänge:

{ 
    "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"] 
}