Reputation: 69
I'm new with Python, and I'm trying to filter a list of DNA sequences (strings) based on a condition.
Given my random list of DNA sequences, I want to keep in the list only the sequences in which A=T and C=G.
This is what I did so far, but I obtain the position of the string and not the string. I wonder how could I obtain a string in my output. Any advice would be great, thank you!
This is what I tried to do so far:
import numpy as np
BASES = ('A','C','T','G')
P = (0.2, 0.3, 0.2, 0.3)
def random_dna_sequence(length):
return ''.join(np.random.choice(BASES, p=P) for _ in range(length))
dna = [random_dna_sequence(20) for _ in range(300)] #dna1=300 sequences of 20 characters each
print(dna)
Then, I tried to obtain the list of sequences that only accomplish this condition:
# Obtain a list dna_2 with DNA sequences that accomplish this condition only
dna_2 = [i for i in range(len(dna)) if (dna[i].count('A'))== (dna[i].count('T')) and (dna[i].count('C'))== (dna[i].count('G'))]
print(dna_2)
My output is returning the position of the sequences that accomplish this condition, but not the sequence itself (the sequence):
[29, 41, 66, 85, 88, 117, 142, 174, 201, 226, 231, 246, 250, 279, 294, 299, 306, 338, 370, 372, 381, 404, 420, 486, 519, 579]
And my desire output should be:
['AACTGACTTG', ...]
Thank you all!
Upvotes: 0
Views: 1224
Reputation: 11
You can just use the filter function with a lambda expression. The filter function algorithm is optimized under the hood.
You should learn the lambda syntax though. Lambdas are just inline functions.
Here is the syntax for your problem:
random_dna_sequencies = [random_dna_sequence(20) for _ in range(300)]
filtered_dna_sequencies_iterator = filter(lambda dna_sequency:
dna_sequency.count('A') == dna_sequency.count('T') and
dna_sequency.count('C') == dna_sequency.count('G'),
random_dna_sequencies)
filtered_dna_sequencies_list = list(filtered_dna_sequencies_iterator)
print(filtered_dna_sequencies_list)
Let me explain:
filter()
function receives two parameters:
random_dna_sequencies
(which means each dna sequency) is passed to the lambda function as argument, named as dna_sequency
. The pameter is tested in the condition dna_sequency.count('A') == dna_sequency.count('T') and dna_sequency.count('C') == dna_sequency.count('G')
. Only the ones who satisfy the condition are returned to the variable filtered_dna_sequencies_iterator
.filter()
function returns an iterator, not a list. If you want the object only to place it in a for
loop, use the iterator. If you want to store the object on lists, you use the cast filtered_dna_sequencies_list = list(filtered_dna_sequencies_iterator)
.Upvotes: 0
Reputation: 69
For a more elegant solution just iterate over the list rather than iterating over the index:
dna_2 = [this_dna for this_dna in dna if (this_dna.count('A'))== (this_dna.count('T')) and (this_dna .count('C'))== (this_dna.count('G'))]
Upvotes: 0
Reputation: 81594
dna_2 = [i for i in range(len(dna)) if (dna[i].count('A'))== (dna[i].count('T')) and (dna[i].count('C'))== (dna[i].count('G'))]
i
here refers to the index (which you probably know but mistyped since you are using dna[i]
when calling .count
).
You can change it to dna_2 = [dna[i] for i ...]
or better yet, just iterate directly over the sequence strings instead of superficially using the indexes:
dna_2 = [sequence for sequence in dna if sequence.count('A') ... ]
Upvotes: 1
Reputation: 54
That should be
dna_2 = [dna[i] for i in range(len(dna)) if (dna[i].count('A'))== (dna[i].count('T')) and (dna[i].count('C'))== (dna[i].count('G'))]
instead.
Upvotes: 1