Insérer datatables manquantes dans les blocs

Je suis un biologiste et j'essaie de résoudre ce problème, s'il vous plaît me guider sur l'endroit où commencer. Je ne sais pas quel forum pour postr ceci, s'il vous plaît laissez-moi savoir si cet endroit n'est pas approprié.

J'ai des blocs de valeurs qui peuvent être ssortingctement soit de deux sources, soit un mélange des sources.

'source1', 'source2' and 'mixture' sont des mots keys dans datatables réelles.

Les valeurs de la source sont limitées dans l'set { AA, TT, GG , CC }

Les valeurs de mélange sont limitées dans l'set { AA , TT , GG , CC , AT , AG, AC , TG , TC , GC } mais les valeurs de mélange dépendent de leur source dans le même bloc. Donc, si dans blockN,

  source1 =XX where X~{A,T,G,C} source2 =YY where Y~{A,T,G,C} 

alors les valeurs de mélange doivent être parmi { XX, YY, XY }

Parfois, l'une ou les deux sources sont absentes de mes données, dans ce cas, je veux insert les valeurs source manquantes,

Si dans un bloc, Source1 est manquant, Source2 est XX , et une des valeurs de mélange est YY , alors nous soaps que Source1 est YY . Un autre exemple est si dans un bloc, Source1 est manquant, Source2 est XX , et une des valeurs de mélange est XY , alors Source1 est YY . Comme vous pouvez le voir, il existe plus de 2 façons de connaître la source en fonction de ce qui est présent dans l'set de mélange.

Il peut y avoir des cas où les deux sources sont absentes, mais il y a des valeurs de mélange XY dans le bloc. Cela nous dit que Source1 et Source2 sont XX et YY (ou YY and XX , l'ordre ne count pas).

Si mes données d'exemple sont

 block1 source1 AA block1 source2 TT block1 mixture AT block1 mixture AA block1 mixture TT block2 source1 GG block2 source2 TT block2 mixture TG block2 mixture TG block2 mixture TT block3 source1 AA block3 source2 TT block3 mixture AT block3 mixture AA block3 mixture TT block4 mixture AT block4 mixture AA block4 mixture TT block5 source2 TT block5 mixture TG block5 mixture TG 

La sortie que je veux est

 block1 source1 AA block1 source2 TT block1 mixture AT block1 mixture AA block1 mixture TT block2 source1 GG block2 source2 TT block2 mixture TG block2 mixture TG block2 mixture TT block3 source1 AA block3 source2 TT block3 mixture AT block3 mixture AA block3 mixture TT block4 source1 AA block4 source2 TT block4 mixture AT block4 mixture AA block4 mixture TT block5 source1 GG block5 source2 TT block5 mixture TG block5 mixture TG 

S'il vous plaît noter les insertions dans les blocs 4 et 5. J'ai séparé les blocs pour faciliter la compréhension; dans datatables réelles, ils ne sont pas séparés par des lignes vides.

On dirait que cela pourrait être fait d'une manière plus simple, mais le meilleur que je puisse find après une heure de scratch est ce script python :

 #! /usr/bin/env python3 import sys, os class Block: block_id = '' source1 = '' source2 = '' mixtures = [] def __init__(self, block_id = '', source1 = '', source2 = '', mixtures = []): self.block_id = block_id self.mixtures = mixtures self.source1 = source1 self.source2 = source2 # Convert mixtures to a set of characters. For example, # ''.join(["AT", "TT"]) # creates the ssortingng "ATTT". set() then converts that ssortingng to # a set of characters {'A', 'T'} sources = set(''.join(mixtures)) # If a source is empty, we take from the set the first element (pop()) # after removing the other source (difference()). Since the set # contains single characters, we double it to get "AA", "TT", etc. if self.source1 == '': self.source1 = sources.difference(set(self.source2)).pop()*2 sources.remove (self.source1[0]) if self.source2 == '': self.source2 = sources.pop()*2 def print (self): print (self.block_id, "source1", self.source1) print (self.block_id, "source2", self.source2) for mix in self.mixtures: print (self.block_id, "mixture", mix) if len(sys.argv) == 1: files = [os.stdin] else: files = (open(f) for f in sys.argv[1:]) for f in files: # Read in all the lines data = [line for rawline in f for line in [rawline.ssortingp().split(' ')]] # Get the unique block IDs blocks = set (lines[0] for line in data) # For each block ID for b in blocks: # The corresponding mixtures mix = [line[2] for line in data if line[0] == b and "mixture" == line[1]] # If "source1 XX" is present, we will get the list ['XX'], and [] if # source1 is not present. ''.join() allows us to flatten ['XX'] to # just 'XX' (and doesn't affect []). Similarly for source2. source1 = ''.join(d[2] for line in data if line[0] == b and "source1" == line[1]) source2 = ''.join(d[2] for line in data if line[0] == b and "source2" == line[1]) # Create an object of the class defined above, and print it. # Initialization fills up the blank values. Block(b, source1, source2, mix).print() 

Même dans ce cas, cela produira des résultats randoms et non block3 (c'est-à-dire block3 données du block3 peuvent block1 , etc.).

Enregistrez-le dans un script (disons, insert.py ) et exécutez:

 python3 insert.py inputfile 

Je l'ai réécrit dans awk :

 #! /usr/bin/awk -f function build (block, source1, source2, sources, mixtures) { if (! source1) { for (char in sources) { if (source2 != char char) { source1 = char char delete sources[char] break } } } if (! source2) { for (char in sources) { if (source1 != char char) { source2 = char char delete sources[char] break } } } printf "%s %s %s\n", block, "source1", source1 printf "%s %s %s\n", block, "source2", source2 for (m in mixtures) { for (i = 0; i < mixtures[m]; i++) { printf "%s %s %s\n", block, "mixture", m } } } { if (prev != $1) { if (prev in data) { build(prev, source1, source2, sources, mixtures) } prev = $1 source1 = "" source2 = "" delete sources delete mixtures } data[$1]++ if ($2 == "source1") {source1 = $3; next} if ($2 == "source2") {source2 = $3; next} if ($2 == "mixture") { mixtures[$3]++ split ($3, chars, "") for (i=1; i <= length($3); i++) { sources[chars[i]]++ } } } END { build(prev, source1, source2, sources, mixtures) } 

Enregistrez-le dans un script (par exemple insert.awk ), chmod +x it et exécutez-le:

 ./insert.awk inputfile 

Maintenant, il devrait conserver l'ordre aussi. Notez que j'ai utilisé delete , qui peut ne pas être présent dans certains awks (mais devrait être dans GNU awk, et mawk).