MOOC Project Work - Sequence Analysis - Data Analysis With Python 2021
MOOC Project Work - Sequence Analysis - Data Analysis With Python 2021
Open menu
Sequence_analysis
Below are some "suggested" imports. Feel free to use and modify these, or not. Generally it's
good practice to keep most or all imports in one place. Typically very close to the start of
notebooks.
import numpy as np
from numpy.random import choice
https://dap-21.mooc.fi/sequence_analysis 1/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
The automated TMC tests do not test cell outputs. These are intended to be evaluated in the
peer reviews. So it is still be a good idea to make the outputs as clear and informative as
possible.
To keep TMC tests running as well as possible it is recommended to keep global variable
assignments in the notebook to a minimum to avoid potential name clashes and confusion.
Additionally you should keep all actual code exection in main guards to keep the test running
smoothly. If you run check_sequence.py in the part07-e01_sequence_analysis folder, the
script should finish very quickly and optimally produce no output.
If you download data from the internet during execution (codon usage table), the parts where
downloading is done should not work if you decide to submit to the tmc server. Local tests
should work fine.
Parts of a DNA molecule can transcribe into an RNA molecule. In this process, thymine gets
replaced by uracil (U).
1. Write a function dna_to_rna to convert a given DNA sequence s into an RNA sequence. For the sake of
exercise, use dict() to store the symbol to symbol encoding rules. Create a program to test your
function.
https://dap-21.mooc.fi/sequence_analysis 2/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
def dna_to_rna(s):
return "".join("U" for _ in s)
if __name__ == '__main__':
print(dna_to_rna("AACGTGATTTC"))
UUUUUUUUUUU
Idea of solution
fill in
Discussion
fill in
Proteins
Like DNA and RNA, protein molecule can be interpreted as a chain of smaller molecules,
where the bases are now amino acids. RNA molecule may translate into a protein molecule,
but instead of base by base, three bases of RNA correspond to one base of protein. That is,
RNA sequence is read triplet (called codon) at a time.
def get_dict():
return {}
https://dap-21.mooc.fi/sequence_analysis 3/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
if __name__ == '__main__':
codon_to_aa = get_dict()
print(codon_to_aa)
{}
Idea of solution
fill in
Discussion
fill in
3. Use the same conversion table as above, but now write function get_dict_list to read the table into a
dict(), such that for each amino acid the hash table stores the list of codons encoding it.
def get_dict_list():
return {}
if __name__ == '__main__':
aa_to_codons = get_dict_list()
print(aa_to_codons)
{}
Idea of solution
fill in
Discussion
fill in
With the conversion tables at hand, the following should be trivial to solve.
https://dap-21.mooc.fi/sequence_analysis 4/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
4. Fill in function rna_to_prot in the stub solution to convert a given DNA sequence s into a protein
sequence. You may use the dictionaries from exercises 2 and 3. You can test your program with
ATGATATCATCGACGATGTAG.
def rna_to_prot(s):
return ""
def dna_to_prot(s):
return rna_to_prot(dna_to_rna(s))
if __name__ == '__main__':
print(dna_to_prot("ATGATATCATCGACGATGTAG"))
Idea of solution
fill in
Discussion
fill in
You may notice that there are 43 = 64 different codons, but only 20 amino acids. That is,
some triplets encode the same amino acid.
Reverse translation
It has been observed that among the codons coding the same amino acid, some are more
frequent than others. These frequencies can be converted to probabilities. E.g. consider
codons AUU, AUC, and AUA that code for amino acid isoleucine. If they are observed, say, 36,
https://dap-21.mooc.fi/sequence_analysis 5/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
47, 17 times, respectively, to code isoleucine in a dataset, the probability that a random such
event is AUU → isoleucine is 36/100.
This phenomenon is called codon adaptation, and for our purposes it works as a good
introduction to generation of random sequences under constraints.
def get_probabability_dict():
return {}
if __name__ == '__main__':
codon_to_prob = get_probabability_dict()
items = sorted(codon_to_prob.items(), key=lambda x: x[0])
for i in range(1 + len(items)//6):
print("\t".join(
f"{k}: {v:.6f}"
for k, v in items[i*6:6+i*6]
))
Idea of solution
fill in
Discussion
fill in
https://dap-21.mooc.fi/sequence_analysis 6/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
Now you should have everything in place to easily solve the following.
6. Write a class ProteinToMaxRNA with a convert method which converts a protein sequence into the
most likely RNA sequence to be the source of this protein. Run your program with LTPIQNRA.
class ProteinToMaxRNA:
def __init__(self):
pass
if __name__ == '__main__':
protein_to_rna = ProteinToMaxRNA()
print(protein_to_rna.convert("LTPIQNRA"))
Idea of solution
fill in
Discussion
fill in
Now we are almost ready to produce random RNA sequences that code a given protein
sequence. For this, we need a subroutine to sample from a probability distribution. Consider
our earlier example of probabilities 36/100, 47/100, and 17/100 for AUU, AUC, and AUA,
respectively. Let us assume we have a random number generator random() that returns a
random number from interval [0, 1). We may then partition the unit interval according to
https://dap-21.mooc.fi/sequence_analysis 7/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
7. Write a function random_event that chooses a random event, given a probability distribution (set of
events whose probabilities sum to 1). You can use function random.uniform to produce values
uniformly at random from the range [0, 1). The distribution should be given to your function as a
dictionary from events to their probabilities.
def random_event(dist):
"""
Takes as input a dictionary from events to their probabilities.
Return a random event sampled according to the given distribution.
The probabilities must sum to 1.0
"""
return next(iter(dist))
if __name__ == '__main__':
distribution = dict(zip("ACGT", [0.10, 0.35, 0.15, 0.40]))
print(", ".join(random_event(distribution) for _ in range(29)))
A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A,
A, A
Idea of solution
fill in
Discussion
fill in
8. Write a class ProteinToRandomRNA to produce a random RNA sequence encoding the input protein
sequence according to the input codon adaptation probabilities. The actual conversion is done through
https://dap-21.mooc.fi/sequence_analysis 8/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
def __init__(self):
pass
if __name__ == '__main__':
protein_to_random_codons = ProteinToRandomRNA()
print(protein_to_random_codons.convert("LTPIQNRA"))
Idea of solution
fill in
Discussion
fill in
https://dap-21.mooc.fi/sequence_analysis 9/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
to just use a sliding window of fixed size, say k , and compute for each window position
T [i..i + k − 1] the base frequencies, where T [1..n] is the input DNA sequence. When
sliding the window from T [i..i + k − 1] to T [i + 1..i + k] frequency f (T [i]) gets decreases
by one and f (T [i + k]) gets increased by one.
Here is an example of a generator expression that works similarily to the built in range
generator:
A yield expression can be used to return a value and temporarily return from the
function.
def sliding_window(s, k):
"""
This function returns a generator that can be iterated over all
starting position of a k-window in the sequence.
For each starting position the generator returns the nucleotide frequencies
in the window as a dictionary.
"""
for _ in s:
https://dap-21.mooc.fi/sequence_analysis 10/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
yield {}
if __name__ == '__main__':
s = "TCCCGACGGCCTTGCC"
for d in sliding_window(s, 4):
print(d)
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
Idea of solution
fill in
Discussion
fill in
https://dap-21.mooc.fi/sequence_analysis 11/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
Our models so far have been so-called zero-order models, as each event has been
independent of other events. With sequences, the dependencies of events are naturally
encoded by their contexts. Considering that a sequence is produced from left-to-right, a first-
order context for T [i] is T [i − 1], that is, the immediately preceding symbol. First-order
Markov chain is a sequence produced by generating c = T [i] with the probability of event of
seeing symbol c after previously generated symbol a = T [i − 1]. The first symbol of the
chain is sampled according to the zero-order model.
The first-order model can naturally be extended to contexts of length k , with T [i] depending
on T [i − k..i − 1]. Then the first k symbols of the chain are sampled according to the zero-
order model. The following assignments develop the routines to work with the higher-order
Markov chains. In what follows, a k -mer is a substring T [i..i + k − 1] of the sequence at an
arbitrary position.
10. Write function context_list that given an input DNA sequence T associates to each k -mer W the
concatenation of all symbols c that appear after context W in T , that is, T [i..i + k] = W c. For
example, GA is associated to TCT in T =ATGATATCATCGACGATGTAG, when k = 2.
if __name__ == '__main__':
k = 2
s = "ATGATATCATCGACGATCTAG"
d = context_list(s, k)
print(d)
{}
Idea of solution
https://dap-21.mooc.fi/sequence_analysis 12/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
fill in
Discussion
fill in
11. With the above solution, write function context_probabilities to count the frequencies of symbols
in each context and convert these frequencies into probabilities. Run context_probabilities with
T = ATGATATCATCGACGATGTAG and k values 0 and 2.
if __name__ == '__main__':
pass
Idea of solution
fill in
Discussion
fill in
12. With the above solution and the function random_event from the earlier exercise, write class
MarkovChain. Its generate method should generate a random DNA sequence following the original k -
th order Markov chain probabilities.
class MarkovChain:
https://dap-21.mooc.fi/sequence_analysis 13/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
def generate(self, n, seed=None):
return "$" * n
if __name__ == '__main__':
zeroth = {'A': 0.2, 'C': 0.19, 'T': 0.31, 'G': 0.3}
kth = {'GT': {'A': 1.0, 'C': 0.0, 'T': 0.0, 'G': 0.0},
'CA': {'A': 0.0, 'C': 0.0, 'T': 1.0, 'G': 0.0},
'TC': {'A': 0.5, 'C': 0.0, 'T': 0.0, 'G': 0.5},
'GA': {'A': 0.0, 'C': 0.3333333333333333, 'T': 0.6666666666666666, 'G': 0.0},
'TG': {'A': 0.5, 'C': 0.0, 'T': 0.5, 'G': 0.0},
'AT': {'A': 0.2, 'C': 0.4, 'T': 0.0, 'G': 0.4},
'TA': {'A': 0.0, 'C': 0.0, 'T': 0.5, 'G': 0.5},
'AC': {'A': 0.0, 'C': 0.0, 'T': 0.0, 'G': 1.0},
'CG': {'A': 1.0, 'C': 0.0, 'T': 0.0, 'G': 0.0}}
n = 10
seed = 0
mc = MarkovChain(zeroth, kth)
print(mc.generate(n, seed))
$$$$$$$$$$
Idea of solution
fill in
Discussion
fill in
If you have survived so far without problems, please run your program a few more times with
different inputs. At some point you should get a lookup error in your hash-table! The reason
for this is not your code, but the way we defined the model: Some k -mers may not be among
the training data (input sequence T ), but such can be generated as the first k -mer that is
generated using the zero-order model.
https://dap-21.mooc.fi/sequence_analysis 14/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
A general approach to fixing such issues with incomplete training data is to use pseudo counts.
That is, all imaginable events are initialized to frequency count 1.
13. Write a new solution context_pseudo_probabilities based on the solution to problem 11. But this
time use pseudo counts in order to obtain a k -th order Markov chain that can assign a probability for any
DNA sequence. You may use the standard library function itertools.product to iterate over all k -mer
of given length (product("ACGT", repeat=k)).
def context_pseudo_probabilities(s, k):
return {"": ""}
if __name__ == '__main__':
k = 2
s = "ATGATATCATCGACGATGTAG"
kth = context_pseudo_probabilities(s, k)
zeroth = context_pseudo_probabilities(s, 0)[""]
print(f"zeroth: {zeroth}")
print("\n".join(f"{k}: {dict(v)}" for k, v in kth.items()))
zeroth:
: {}
$$$$$$$$$$$$$$$$$$$$
Idea of solution
fill in
Discussion
fill in
https://dap-21.mooc.fi/sequence_analysis 15/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
14. Write class MarkovProb that given the k -th order Markov chain developed above to the constructor, its
method probability computes the probability of a given input DNA sequence.
class MarkovProb:
def __init__(self, k, zeroth, kth):
self.k = k
self.zeroth = zeroth
self.kth = kth
if __name__ == '__main__':
k = 2
kth = context_pseudo_probabilities("ATGATATCATCGACGATGTAG", k)
zeroth = context_pseudo_probabilities("ATGATATCATCGACGATGTAG", 0)[""]
mc = MarkovProb(2, zeroth, kth)
s="ATGATATCATCGACGATGTAG"
print(f"Probability of sequence {s} is {mc.probability(s)}")
Idea of solution
fill in
Discussion
fill in
With the last assignment you might end up in trouble with precision, as multiplying many
small probabilities gives a really small number in the end. There is an easy fix by using so-
called log-transform. Consider computation of P = s1 s2 ⋯ sn , where 0 ≤ si ≤ 1 for each
repeated application of the property that the logarithm of a multiplication of two numbers is
the sum of logarithms of the two numbers taken separately. The results is abbreviated as log-
probability.
15. Write class MarkovLog that given the k -th order Markov chain developed above to the constructor, its
method log_probability computes the log-probability of a given input DNA sequence. Run your
program with T = ATGATATCATCGACGATGTAG and k = 2.
class MarkovLog(object):
if __name__ == '__main__':
k = 2
kth = context_pseudo_probabilities("ATGATATCATCGACGATGTAG", k)
zeroth = context_pseudo_probabilities("ATGATATCATCGACGATGTAG", 0)[""]
mc = MarkovLog(2, zeroth, kth)
s="ATGATATCATCGACGATGTAG"
print(f"Log probability of sequence {s} is {mc.log_probability(s)}")
Idea of solution
fill in
Discussion
fill in
https://dap-21.mooc.fi/sequence_analysis 17/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
Finally, if you try to use the code so far for very large inputs, you might observe that the
concatenation of symbols following a context occupy considerable amount of space. This is
unnecessary, as we only need the frequencies.
16. Optimize the space requirement of your code from exercise 13 for the k -th order Markov chain by
replacing the concatenations by direct computations of the frequencies. Implement this as the
better_context_probabilities function.
if __name__ == '__main__':
k = 2
s = "ATGATATCATCGACGATGTAG"
d = better_context_probabilities(s, k)
print("\n".join(f"{k}: {v}" for k, v in d.items()))
Idea of solution
fill in
Discussion
fill in
While the earlier approach of explicit concatenation of symbols following a context suffered
from inefficient use of space, it does have a benefit of giving another much simpler strategy
to sample from the distribution: observe that an element of the concatenation taken
uniformly randomly is sampled exactly with the correct probability.
17. Revisit the solution 12 and modify it to directly sample from the concatenation of symbols following a
context. The function np.random.choice may be convenient here. Implement the modified version as
https://dap-21.mooc.fi/sequence_analysis 18/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
if __name__ == '__main__':
k = 2
s = "ATGATATCATCGACGATGTAG"
n = 10
seed = 7
mc = SimpleMarkovChain(s, k)
print(mc.generate(n, seed))
QQQQQQQQQQ
Idea of solution
fill in
Discussion
fill in
k -mer index
Our k -th order Markov chain can now be modified to a handy index structure called k -mer
index. This index structure associates to each k -mer its list of occurrence positions in DNA
sequence T . Given a query k -mer W , one can thus easily list all positions i with
T [i..k − 1] = W .
https://dap-21.mooc.fi/sequence_analysis 19/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
18. Implement function kmer_index inspired by your earlier code for the k -th order Markov chain. Test your
program with ATGATATCATCGACGATGTAG and k = 2.
def kmer_index(s, k):
return {}
if __name__ == '__main__':
k=2
s = "ATGATATCATCGACGATGTAG"
print("Using string:")
print(s)
print("".join([str(i%10) for i in range(len(s))]))
print(f"\n{k}-mer index is:")
d=kmer_index(s, k)
print(dict(d))
Using string:
ATGATATCATCGACGATGTAG
012345678901234567890
Idea of solution
fill in
Discussion
fill in
n n
the same set of n events. This means ∑i=1 pi = ∑i=1 qi = 1, 0 ≤ pj ≤ 1, and
Kullback-Leibler divergence is a measure d() for the relative entropy of P with respect to Q
n
defined as d(P ∣∣Q) = ∑i=1 pi log p
i
qi .
This measure is always non-negative, and 0 only when P = Q. It can be interpreted as the
gain of knowing Q to encode P . Note that this measure is not symmetric.
19. Write function kullback_leibler to compute d(P ∣∣Q). Test your solution by
generating a random RNA sequence encoding the input protein sequence according to
the input codon adaptation probabilities. Then you should learn the codon adaptation
probabilities from the RNA sequence you generated. Then try the same with uniformly
random RNA sequences (which don't have to encode any specific protein sequence).
Compute the relative entropies between the three distribution (original, predicted,
uniform) and you should observe a clear difference. Because d(P ∣∣Q) is not symmetric,
you can either print both d(P ∣∣Q) and d(Q∣∣P ), or their average.
This problem may be fairly tricky. Only the kullback_leibler function is automatically
tested. The codon probabilities is probably a useful helper function. The main guarded
section can be completed by filling out the pass sections using tooling from previous
parts and fixing the placeholder lines.
def codon_probabilities(rna):
"""
Given an RNA sequence, simply calculates the proability of
all 3-mers empirically based on the sequence
"""
https://dap-21.mooc.fi/sequence_analysis 21/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
return {"".join(codon): 0 for codon in product("ACGU", repeat=3)}
if __name__ == '__main__':
aas = list("*ACDEFGHIKLMNPQRSTVWY") # List of amino acids
n = 10000
# Maybe check that converting back to protein results in the same sequence
pass
# Create a completely random RNA sequence and get the codon probabilities
pass
cp_uniform = codon_probabilities("<random rna sequence>") # placeholder call
https://dap-21.mooc.fi/sequence_analysis 22/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
Idea of solution
fill in
Discussion
fill in
probability of the j th nucleotide on the condition the previous nucleotide was the ith. An
example of a transition matrix is
\begin{array}{l|rrrr} & A & C & G & T \ \hline A & 0.30 & 0.0 & 0.70 & 0.0 \ C & 0.00 & 0.4 &
0.00 & 0.6 \ G & 0.35 & 0.0 & 0.65 & 0.0 \ T & 0.00 & 0.2 & 0.00 & 0.8 \ \end{array}.
product).
20. Write function get_stationary_distributions that gets a transition matrix as parameter, and
returns the list of stationary distributions. You can do this with NumPy by first taking transposition of
https://dap-21.mooc.fi/sequence_analysis 23/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
both sides of the above equation to get equation π T = P T π T . Using numpy.linalg.eig take all
eigenvectors related to eigenvalue 1.0. By normalizing these vectors to sum up to one get the stationary
distributions of the original transition matrix. In the main function print the stationary distributions of the
above transition matrix.
def get_stationary_distributions(transition):
"""
The function get a transition matrix of a degree one Markov chain as parameter.
It returns a list of stationary distributions, in vector form, for that chain.
"""
return np.random.rand(2, 4) - 0.5
if __name__ == "__main__":
transition=np.array([[0.3, 0, 0.7, 0],
[0, 0.4, 0, 0.6],
[0.35, 0, 0.65, 0],
[0, 0.2, 0, 0.8]])
print("\n".join(
", ".join(
f"{pv:+.3f}"
for pv in p)
for p in get_stationary_distributions(transition)))
Idea of solution
Discussion
21. Implement the kl_divergence function below so that the main guarded code runs properly. Using your
modified Markov chain generator generate a nucleotide sequence s of length 10 000. Choose prefixes of
s of lengths 1, 10, 100, 1000, and 10 000. For each of these prefixes find out their nucleotide
distribution (of order 0) using your earlier tool. Use 1 as the pseudo count. Then, for each prefix, compute
the KL divergence between the initial distribution and the normalized nucleotide distribution.
https://dap-21.mooc.fi/sequence_analysis 24/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
if __name__ == "__main__":
transition=np.array([[0.3, 0, 0.7, 0],
[0, 0.4, 0, 0.6],
[0.35, 0, 0.65, 0],
[0, 0.2, 0, 0.8]])
print("Transition probabilities are:")
print(transition)
stationary_distributions = get_stationary_distributions(transition)
print("Stationary distributions:")
print(np.stack(stationary_distributions))
initial = stationary_distributions[1]
print("Using [{}] as initial distribution\n".format(", ".join(f"{v:.2f}" for v in initial)))
results = kl_divergences(initial, transition)
for prefix_length, divergence in results: # iterate on prefix lengths in order (1, 10, 100...)
print("KL divergence of stationary distribution prefix " \
"of length {:5d} is {:.8f}".format(prefix_length, divergence))
Idea of solution
fill in
Discussion
fill in
22. Implement the following in the main function. Find the stationary distribution for the following transition
matrix:
\begin{array}{ l | r r r r} & A & C & G & T \ \hline A & 0.30 & 0.10 & 0.50 & 0.10 \ C & 0.20 &
0.30 & 0.15 & 0.35 \ G & 0.25 & 0.15 & 0.20 & 0.40 \ T & 0.35 & 0.20 & 0.40 & 0.05 \ \end{array}
Since there is only one stationary distribution, it is called the equilibrium distribution. Choose
randomly two nucleotide distributions. You can take these from your sleeve or sample them
from the Dirichlet distribution. Then for each of these distributions as the initial distribution
of the Markov chain, repeat the above experiment.
The main function should return tuples, where the first element is the (random) initial
distribution and the second element contains the results as a list of tuples where the first
element is the kl divergence and the second element the empirical nucleotide distribution, for
the different prefix lengths.
The state distribution should converge to the equilibrium distribution no matter how we start
the Markov chain! That is the last line of the tables should have KL-divergence very close to 0
and an empirical distribution very close to the equilibrium distribution.
https://dap-21.mooc.fi/sequence_analysis 26/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
if __name__ == "__main__":
transition = np.array([[0.3, 0.1, 0.5, 0.1],
[0.2, 0.3, 0.15, 0.35],
[0.25, 0.15, 0.2, 0.4],
[0.35, 0.2, 0.4, 0.05]])
print("Transition probabilities are:", transition, sep="\n")
stationary_distributions = get_stationary_distributions(transition)
# Uncomment the below line to check that there actually is only one stationary distribution
# assert len(stationary_distributions) == 1
equilibrium_distribution = stationary_distributions[0]
print("Equilibrium distribution:")
print(equilibrium_distribution)
for initial_distribution, results in main(transition, equilibrium_distribution):
print("\nUsing {} as initial distribution:".format(initial_distribution))
print("kl-divergence empirical distribution")
print("\n".join("{:.11f} {}".format(di, kl) for di, kl in results))
https://dap-21.mooc.fi/sequence_analysis 27/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
Idea of solution
fill in
Discussion
fill in
You have reached the end of this section!
Remember to check your points from the ball on the bottom-right corner of the material!
In this part:
https://dap-21.mooc.fi/sequence_analysis 28/29
8/11/24, 8:50 PM Project work: sequence analysis - Data Analysis with Python 2021
This course is created by the Agile Education Research -research group of the University of Helsinki.
https://dap-21.mooc.fi/sequence_analysis 29/29