I'm writing a function that introduces $n$ substitutions inside a sequence of nucleotides. I have a working version, but I'm looking for any other ways of doing this:
from random import choice as random_choice
NUCLEOTIDES = set(["A", "C", "G", "T"])
def randomly_substitute(seq: str, num_mutations: int = 1) -> str:
if num_mutations > len(seq):
raise ValueError(
f"{num_mutations} is greater than the length of the input sequence"
)
index_choices = list(range(len(seq)))
mutated_seq = seq
while num_mutations != 0:
index_choice = random_choice(index_choices)
index_choices = [el for el in index_choices if el != index_choice]
chosen_nucleotide = seq[index_choice]
if chosen_nucleotide not in NUCLEOTIDES:
raise ValueError("Not a nucleotide: {chosen_nucleotide}")
possible_mutations = [el for el in NUCLEOTIDES if el != chosen_nucleotide]
chosen_mutation = random_choice(possible_mutations)
mutated_seq = (
mutated_seq[:index_choice]
+ chosen_mutation
+ mutated_seq[index_choice + 1 :]
)
num_mutations -= 1
return mutated_seq
In particular, the function maintains a list called index_choices
that is of size len(seq)
, and keeps re-building this list after each introduced substitution. This feels not very efficient.