Professional Documents
Culture Documents
An Intuitive Approach To DTW - Dynamic Time Warping
An Intuitive Approach To DTW - Dynamic Time Warping
An Intuitive Approach To DTW - Dynamic Time Warping
Search Write
106
S ince you are here, I assume you already know the reason why we use
Dynamic Time Warping, or DTW in time-series data. Simply put, it’s
used to align or match two similar patterns.
A brief overview
There are several awesome real life situations were DTW just rocks — if you
do not know them already, I recommend getting to know them — they are
really fun!
You can read more about DTW here and about it’s many applications here (refer
the Introduction section)
I love this algorithm! In essence, it is one of those short and elegant algos
which pack a punch. It is a classic example of finding the shortest path
using the Dynamic Programming approach.
I have had colleagues running away from understanding the inner workings
of the algo as it involves recursion. This eventually stops them from
understanding the nuances of the approach and from learning how to tweak
it as per their requirements.
— Stephen Hawking
Imagine you are standing at the blue square and wish to go to the red square.
All the numbers that you see in the cells along the path, correspond to the
toll amount you have to pay at each step (arbitrarily decided, for now). If I
were to ask you, “Tell me the least amount one needs to spend to reach from blue
to red”, how would you do it?
Another way to say the above fact is that, “You can arrive at any square only
from one of the 3 adjacent squares”:
A ‘brute-force’ way would be to try all the paths possible from the blue to the
red square and choose the cheapest one. However, dynamic programming
and recursion give us a better, smarter way.
I like to solve all recursion problems by thinking as ‘the lazy boss’ who has
uncountable minions at his disposal to do the job. If someone asked me
to solve the above problem, I would simply say, “Minions A, B and C, tell me
the least cost to reach the 3 squares surrounding the red square, and then I’ll
calculate the answer in a minute. Till then, don’t bother me.”
Suppose by some magic (which you are not interested in knowing about), the
minions bring you the answer, marked in green cells:
Answers of Minions A, B and C — “Image by author”
All I need to do now is find the minimum of (10, 7, 7), which is 7 and then
add current square’s cost, which is 2. This gives me the answer as 9. Done!
9 is the minimum cost of travelling from blue to red. But wait, how did the
minions come up with the green values? They of course, emulate you and act
as lazy bosses too!
Each minion gets hold of 3 junior minions (the damned hierarchy in the
office, I tell you!) and tells them to bring them least cost values for their 3
neighbourhood/adjacent squares. Here’s an animation to better explain this:
This keeps going on and on, with each junior minion ‘magically’ getting its
answer. But for how long? Surely it ends sometime? Yes, it does. When there
is no way to subdivide the work further. When a minion gets the task to
calculate the cost at the blue square, he can’t delegate it to anyone else, as
there is no neighbourhood to go to. He just needs to know that the cost there
is zero.
That’s it. You can translate this into a recursive python function in just a few
lines of code:
if (i<0) | (j<0):
return np.inf
Notice how I have returned np.inf (infinity) when either i or j is less than
zero. This is just a way to ignore the neighbour which doesn’t exist. For
example, when you are in a top-row square, the only neighbour you need to
consider is the left one, as there’s no square above the current square.
Similar logic goes for squares in the first column, where there’s no
neighbour to the left.
output_cost = cheapest(cost, 3, 4)
print(output_cost)
If you call it for all the squares, you can finally create a cheapest cost matrix
as output:
Output:
[[ 0, 2, 7, 8, 9],
[ 5, 3, 6, 8, 10],
[ 6, 4, 9, 7, 10],
[ 7, 7, 6, 7, 9]]
So, what would be the cheapest path from the blue square to the red square?
We just need to track the minimum-neighbour around each square. Here’s the
code if you want to print the path too. This is certainly not optimized, but is
simple to understand:
Let’s see the path returned from blue to red square by calling:
trace_path(output_cost_matrix, 3, 4)
Output:
[(0, 0), (0, 1), (1, 2), (2, 3), (3, 4)]
Let’s look at the mapping of two signals again. The one in cyan is pattern1
and the one in orange is pattern2, with the red lines trying to find a
corresponding point on pattern1 for every point on pattern2:
Pattern mapping — “Image by author”
You have various choices you can pick from here, as per your use-case, but
the most common one is the euclidean distance between those points.
You arrange all pattern1-points as column axis of the matrix and all
pattern2-points as row axis. Then fill each square with the euclidean
distance:
And then it’s the recursive algorithm we just went through. An output path
like [(0,0), (0,1), (1,1), (2,2), (3,3), (4,3)] would mean that point 0 in
pattern1 should be matched up with points 0 and 1 in pattern2. Points 1, 2, 3
and 4 in pattern1 should be matched with points 1, 2, 3 and 3 in pattern2.
But what does that actually achieve? What does such shortest-distance
matching mean?
And there you have it. A simple DTW algorithm implemented from scratch.
I have not mentioned several nuances and variations of the DTW process, for
example a windowed DTW where we add a locality constraint. I hope this
article has sparked your interest in knowing more about it. Do let me know if
you discover something cool about it!
Tech enthusiast. I love absorbing new concepts and sharing them in the simplest of ways.
Reach out on: https://www.linkedin.com/in/himanshu-chandra-33512811
714 8 2.3K 19
2.4K 17 31
See all from Himanshu Chandra See all from Towards Data Science
42 50
Lists
ChatGPT prompts
44 stories · 1195 saves
Karolina Kozmana Aggelos K
10 min read · Jan 22, 2024 6 min read · Jan 28, 2024
19.8K 545 11
· 4 min read · Nov 17, 2023 13 min read · Oct 26, 2023
14 277