<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/tsrepr-use-case-clustering-time-series-representations-in-r/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://petolau.github.io/TSrepr-clustering-time-series-representations/"> Peter Laurinec</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>In the previous blog post, I showed you usage of my <a rel="nofollow" href="https://cran.r-project.org/package=TSrepr" target="_blank"><strong>TSrepr</strong></a> package. There was shown what kind of <a rel="nofollow" href="https://petolau.github.io/TSrepr-time-series-representations/" target="_blank">time series representations</a> are implemented and what are they good for.</p>
<p>In this tutorial, I will show you one use case how to use time series representations effectively. This use case is <strong>clustering</strong> of time series and it will be clustering of consumers of electricity load.</p>
<p>By clustering of consumers of electricity load, we can extract typical load <strong>profiles</strong>, improve the accuracy of consequent electricity consumption forecasting, detect anomalies or monitor a whole smart grid (grid of consumers) (Laurinec et al. (2016), Laurinec and Lucká (2016)). I will show you the first use case, the extraction of typical electricity load profiles by <a rel="nofollow" href="https://en.wikipedia.org/wiki/K-medoids" target="_blank"><strong>K-medoids</strong></a> clustering method.</p>
<p>Firstly, let’s load the required packages, data (<code>elec_load</code>) and return the dimensions of the dataset.</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>TSrepr</span><span>)</span><span>
</span><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>library</span><span>(</span><span>data.table</span><span>)</span><span>
</span><span>library</span><span>(</span><span>cluster</span><span>)</span><span>
</span><span>library</span><span>(</span><span>clusterCrit</span><span>)</span><span>
</span><span>data</span><span>(</span><span>&quot;elec_load&quot;</span><span>)</span><span>
</span><span>dim</span><span>(</span><span>elec_load</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1]  50 672</code></pre>
</figure>
<p>There are 50 time series (consumers) of length 672, specifically time series of length 2 weeks of electricity consumption.<br>
These measurements are from smart meters from an unknown country.</p>
<p>It is obvious that dimensionality is too high and the <a rel="nofollow" href="https://en.wikipedia.org/wiki/Curse_of_dimensionality" target="_blank"><strong>curse of dimensionality</strong></a> can happen.<br>
For this reason, we have to reduce dimensionality in some way. One of the best approaches is to use time series representations in order to reduce dimensionality, reduce noise and emphasize the main characteristics of time series.</p>
<p>For double seasonal time series of electricity consumption (daily and weekly seasonality), the model-based representation approaches seem to have best ability to extract typical profiles of consumption.<br>
However, I will use some other representation methods implemented in <strong>TSrepr</strong> too.</p>
<p>Let’s use one of the basic model-based representation methods – <strong>mean seasonal profile</strong>. It is implemented in the <code>repr_seas_profile</code> function and we will use it alongside <code>repr_matrix</code> function that computes representations for every row of a matrix of time series. One more very important notice here, normalisation of time series is a necessary procedure before every clustering or classification of time series. It is due to a fact that we want to extract typical curves of consumption and don’t cluster based on an amount of consumption.<br>
By using the <strong>TSrepr</strong> package, we can do it all in one function – <code>repr_matrix</code>. We will use z-score normalisation implemented in <code>norm_z</code> function.<br>
We have 48 measurements during a day, so set <code>freq = 48</code>.</p>
<figure>
<pre><code data-lang="r"><span>data_seasprof</span><span> </span><span>&lt;-</span><span> </span><span>repr_matrix</span><span>(</span><span>elec_load</span><span>,</span><span> </span><span>func</span><span> </span><span>=</span><span> </span><span>repr_seas_profile</span><span>,</span><span>
</span><span>args</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>freq</span><span> </span><span>=</span><span> </span><span>48</span><span>,</span><span> </span><span>func</span><span> </span><span>=</span><span> </span><span>mean</span><span>),</span><span>
</span><span>normalise</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span> </span><span>func_norm</span><span> </span><span>=</span><span> </span><span>norm_z</span><span>)</span><span>
</span><span>dim</span><span>(</span><span>data_seasprof</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 50 48</code></pre>
</figure>
<p>We can see that dimensionality was in fact reduced significantly. Now, let’s use the K-medoids (<code>pam</code> function from <code>cluster</code> package) clustering method to extract typical consumption profiles.<br>
Since we don’t know a proper number of clusters to create, i.e. a priori information about a number of clusters, an <a rel="nofollow" href="https://en.wikipedia.org/wiki/Cluster_analysis#Internal_evaluation" target="_blank">internal validation index</a> is have to be used to determine an optimal number of clusters.<br>
I will use well known <a rel="nofollow" href="https://en.wikipedia.org/wiki/Davies%E2%80%93Bouldin_index" target="_blank">Davies-Bouldin index</a> for this evaluation. By Davies-Bouldin index computation, we want to find a minimum of its values.</p>
<p>I will set the range of number of clusters to 2-7.</p>
<figure>
<pre><code data-lang="r"><span>clusterings</span><span> </span><span>&lt;-</span><span> </span><span>lapply</span><span>(</span><span>c</span><span>(</span><span>2</span><span>:</span><span>7</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span>
</span><span>pam</span><span>(</span><span>data_seasprof</span><span>,</span><span> </span><span>x</span><span>))</span><span>
</span><span>DB_values</span><span> </span><span>&lt;-</span><span> </span><span>sapply</span><span>(</span><span>seq_along</span><span>(</span><span>clusterings</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>intCriteria</span><span>(</span><span>data_seasprof</span><span>,</span><span> </span><span>as.integer</span><span>(</span><span>clusterings</span><span>[[</span><span>x</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>c</span><span>(</span><span>&quot;Davies_Bouldin&quot;</span><span>)))</span></code></pre>
</figure>
<p>Let’s plot results of internal evaluation.</p>
<figure>
<pre><code data-lang="r"><span>ggplot</span><span>(</span><span>data.table</span><span>(</span><span>Clusters</span><span> </span><span>=</span><span> </span><span>2</span><span>:</span><span>7</span><span>,</span><span> </span><span>DBindex</span><span> </span><span>=</span><span> </span><span>unlist</span><span>(</span><span>DB_values</span><span>)),</span><span>
</span><span>aes</span><span>(</span><span>Clusters</span><span>,</span><span> </span><span>DBindex</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>3</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-4" src="https://i0.wp.com/petolau.github.io/images/post_8/unnamed-chunk-4-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The “best” number of clusters is 7 (lowest value of the index).</p>
<p>Let’s plot the results of clustering with 7 number of clusters. I will use computed medoids stored in the object <code>clustering</code>. For a visualization, the <code>facet_wrap</code> function is very handy here.</p>
<figure>
<pre><code data-lang="r"><span># prepare data for plotting</span><span>
</span><span>data_plot</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>data.table</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>as.factor</span><span>(</span><span>clusterings</span><span>[[</span><span>6</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>data_seasprof</span><span>)))</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>Time</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>ncol</span><span>(</span><span>data_seasprof</span><span>),</span><span> </span><span>each</span><span> </span><span>=</span><span> </span><span>nrow</span><span>(</span><span>data_seasprof</span><span>))]</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>nrow</span><span>(</span><span>data_seasprof</span><span>),</span><span> </span><span>ncol</span><span>(</span><span>data_seasprof</span><span>))]</span><span>
</span><span># prepare medoids</span><span>
</span><span>centers</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>clusterings</span><span>[[</span><span>6</span><span>]]</span><span>$</span><span>medoids</span><span>))</span><span>
</span><span>setnames</span><span>(</span><span>centers</span><span>,</span><span> </span><span>c</span><span>(</span><span>&quot;Var1&quot;</span><span>,</span><span> </span><span>&quot;Var2&quot;</span><span>),</span><span> </span><span>c</span><span>(</span><span>&quot;class&quot;</span><span>,</span><span> </span><span>&quot;Time&quot;</span><span>))</span><span>
</span><span>centers</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>class</span><span>]</span><span>
</span><span># plot the results</span><span>
</span><span>ggplot</span><span>(</span><span>data_plot</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>,</span><span> </span><span>group</span><span> </span><span>=</span><span> </span><span>ID</span><span>))</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span>class</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>scales</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey10&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.65</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>data</span><span> </span><span>=</span><span> </span><span>centers</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>),</span><span>
</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;firebrick1&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.80</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1.2</span><span>)</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;Time&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;Load (normalised)&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-5" src="https://i2.wp.com/petolau.github.io/images/post_8/unnamed-chunk-5-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>We can see 5 typical extracted profiles – red lines (medoids of clusters). The next two clusters are one-elemental, so they can be referred as outliers.</p>
<p>Now, let’s try some more sophisticated method for the extraction of seasonal profiles – <strong>GAM regression coefficients</strong>. By <code>repr_gam</code> function, we can extract double seasonal regression coefficients – daily and weekly (you can read more about the <a rel="nofollow" href="https://petolau.github.io/Analyzing-double-seasonal-time-series-with-GAM-in-R/" target="_blank">analysis of seasonal time series with <strong>GAM</strong> here</a>).<br>
However, the number of weekly seasonal regression coefficients will be only 6, because the number of the second seasonality coefficients is set to freq_2 / freq_1, so 48*7 / 48 = 7, and 7 – 1 = 6 because of splines computation (differentiation). I will again use <code>repr_matrix</code> function.</p>
<figure>
<pre><code data-lang="r"><span>data_gam</span><span> </span><span>&lt;-</span><span> </span><span>repr_matrix</span><span>(</span><span>elec_load</span><span>,</span><span> </span><span>func</span><span> </span><span>=</span><span> </span><span>repr_gam</span><span>,</span><span> </span><span>args</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>freq</span><span> </span><span>=</span><span> </span><span>c</span><span>(</span><span>48</span><span>,</span><span> </span><span>48</span><span>*</span><span>7</span><span>)),</span><span>
</span><span>normalise</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span> </span><span>func_norm</span><span> </span><span>=</span><span> </span><span>norm_z</span><span>)</span><span>
</span><span>dim</span><span>(</span><span>data_gam</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 50 53</code></pre>
</figure>
<p>So the dimension is 47 + 6 = 53 because of usage of splines in GAM method. Let’s cluster the data and visualize results of it.</p>
<figure>
<pre><code data-lang="r"><span>clusterings</span><span> </span><span>&lt;-</span><span> </span><span>lapply</span><span>(</span><span>c</span><span>(</span><span>2</span><span>:</span><span>7</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span>
</span><span>pam</span><span>(</span><span>data_gam</span><span>,</span><span> </span><span>x</span><span>))</span><span>
</span><span>DB_values</span><span> </span><span>&lt;-</span><span> </span><span>sapply</span><span>(</span><span>seq_along</span><span>(</span><span>clusterings</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>intCriteria</span><span>(</span><span>data_gam</span><span>,</span><span> </span><span>as.integer</span><span>(</span><span>clusterings</span><span>[[</span><span>x</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>c</span><span>(</span><span>&quot;Davies_Bouldin&quot;</span><span>)))</span></code></pre>
</figure>
<p>Let’s plot results of internal evaluation.</p>
<figure>
<pre><code data-lang="r"><span>ggplot</span><span>(</span><span>data.table</span><span>(</span><span>Clusters</span><span> </span><span>=</span><span> </span><span>2</span><span>:</span><span>7</span><span>,</span><span> </span><span>DBindex</span><span> </span><span>=</span><span> </span><span>unlist</span><span>(</span><span>DB_values</span><span>)),</span><span>
</span><span>aes</span><span>(</span><span>Clusters</span><span>,</span><span> </span><span>DBindex</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>3</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-8" src="https://i1.wp.com/petolau.github.io/images/post_8/unnamed-chunk-8-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The optimal number of clusters is again 7. Let’s plot results.</p>
<figure>
<pre><code data-lang="r"><span># prepare data for plotting</span><span>
</span><span>data_plot</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>data.table</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>as.factor</span><span>(</span><span>clusterings</span><span>[[</span><span>6</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>data_gam</span><span>)))</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>Time</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>ncol</span><span>(</span><span>data_gam</span><span>),</span><span> </span><span>each</span><span> </span><span>=</span><span> </span><span>nrow</span><span>(</span><span>data_gam</span><span>))]</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>nrow</span><span>(</span><span>data_gam</span><span>),</span><span> </span><span>ncol</span><span>(</span><span>data_gam</span><span>))]</span><span>
</span><span># prepare medoids</span><span>
</span><span>centers</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>clusterings</span><span>[[</span><span>6</span><span>]]</span><span>$</span><span>medoids</span><span>))</span><span>
</span><span>setnames</span><span>(</span><span>centers</span><span>,</span><span> </span><span>c</span><span>(</span><span>&quot;Var1&quot;</span><span>,</span><span> </span><span>&quot;Var2&quot;</span><span>),</span><span> </span><span>c</span><span>(</span><span>&quot;class&quot;</span><span>,</span><span> </span><span>&quot;Time&quot;</span><span>))</span><span>
</span><span>centers</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>class</span><span>]</span><span>
</span><span># plot the results</span><span>
</span><span>ggplot</span><span>(</span><span>data_plot</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>,</span><span> </span><span>group</span><span> </span><span>=</span><span> </span><span>ID</span><span>))</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span>class</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>scales</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey10&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.65</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>data</span><span> </span><span>=</span><span> </span><span>centers</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>),</span><span>
</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;firebrick1&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.80</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1.2</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_vline</span><span>(</span><span>xintercept</span><span> </span><span>=</span><span> </span><span>46</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;dodgerblue2&quot;</span><span>,</span><span>
</span><span>size</span><span> </span><span>=</span><span> </span><span>1.4</span><span>,</span><span> </span><span>linetype</span><span> </span><span>=</span><span> </span><span>5</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.8</span><span>)</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;Time&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;Load (normalised)&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-9" src="https://i1.wp.com/petolau.github.io/images/post_8/unnamed-chunk-9-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>That is a more delightful result, isn’t it? Extracted consumption profiles are smoother than in the case of average seasonal profiles. The blue dashed line borders daily and weekly seasonal coefficients.<br>
The K-medoids now extracted 4 typical profiles and determined 3 one-element clusters.</p>
<p>I will show you also result of clustering of some nondata adaptive representation, let’s pick for example <strong>DFT</strong> (Discrete Fourier Transform) method and extract first 48 DFT coefficients.</p>
<figure>
<pre><code data-lang="r"><span>data_dft</span><span> </span><span>&lt;-</span><span> </span><span>repr_matrix</span><span>(</span><span>elec_load</span><span>,</span><span> </span><span>func</span><span> </span><span>=</span><span> </span><span>repr_dft</span><span>,</span><span> </span><span>args</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>coef</span><span> </span><span>=</span><span> </span><span>48</span><span>),</span><span>
</span><span>normalise</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span> </span><span>func_norm</span><span> </span><span>=</span><span> </span><span>norm_z</span><span>)</span><span>
</span><span>dim</span><span>(</span><span>data_dft</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 50 48</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>clusterings</span><span> </span><span>&lt;-</span><span> </span><span>lapply</span><span>(</span><span>c</span><span>(</span><span>2</span><span>:</span><span>7</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span>
</span><span>pam</span><span>(</span><span>data_dft</span><span>,</span><span> </span><span>x</span><span>))</span><span>
</span><span>DB_values</span><span> </span><span>&lt;-</span><span> </span><span>sapply</span><span>(</span><span>seq_along</span><span>(</span><span>clusterings</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>intCriteria</span><span>(</span><span>data_dft</span><span>,</span><span> </span><span>as.integer</span><span>(</span><span>clusterings</span><span>[[</span><span>x</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>c</span><span>(</span><span>&quot;Davies_Bouldin&quot;</span><span>)))</span></code></pre>
</figure>
<p>Let’s plot results of internal evaluation.</p>
<figure>
<pre><code data-lang="r"><span>ggplot</span><span>(</span><span>data.table</span><span>(</span><span>Clusters</span><span> </span><span>=</span><span> </span><span>2</span><span>:</span><span>7</span><span>,</span><span> </span><span>DBindex</span><span> </span><span>=</span><span> </span><span>unlist</span><span>(</span><span>DB_values</span><span>)),</span><span>
</span><span>aes</span><span>(</span><span>Clusters</span><span>,</span><span> </span><span>DBindex</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>3</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-12" src="https://i2.wp.com/petolau.github.io/images/post_8/unnamed-chunk-12-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>We can see nice <a rel="nofollow" href="https://en.wikipedia.org/wiki/Determining_the_number_of_clusters_in_a_data_set#The_elbow_method" target="_blank">“elbow”</a> here at 4 number of clusters.</p>
<figure>
<pre><code data-lang="r"><span># prepare data for plotting</span><span>
</span><span>data_plot</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>data.table</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>as.factor</span><span>(</span><span>clusterings</span><span>[[</span><span>3</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>data_dft</span><span>)))</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>Time</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>ncol</span><span>(</span><span>data_dft</span><span>),</span><span> </span><span>each</span><span> </span><span>=</span><span> </span><span>nrow</span><span>(</span><span>data_dft</span><span>))]</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>nrow</span><span>(</span><span>data_dft</span><span>),</span><span> </span><span>ncol</span><span>(</span><span>data_dft</span><span>))]</span><span>
</span><span># prepare medoids</span><span>
</span><span>centers</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>clusterings</span><span>[[</span><span>3</span><span>]]</span><span>$</span><span>medoids</span><span>))</span><span>
</span><span>setnames</span><span>(</span><span>centers</span><span>,</span><span> </span><span>c</span><span>(</span><span>&quot;Var1&quot;</span><span>,</span><span> </span><span>&quot;Var2&quot;</span><span>),</span><span> </span><span>c</span><span>(</span><span>&quot;class&quot;</span><span>,</span><span> </span><span>&quot;Time&quot;</span><span>))</span><span>
</span><span>centers</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>class</span><span>]</span><span>
</span><span># plot the results</span><span>
</span><span>ggplot</span><span>(</span><span>data_plot</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>,</span><span> </span><span>group</span><span> </span><span>=</span><span> </span><span>ID</span><span>))</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span>class</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>scales</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey10&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.65</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>data</span><span> </span><span>=</span><span> </span><span>centers</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>),</span><span>
</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;firebrick1&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.80</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1.2</span><span>)</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;Time&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;Load (normalised)&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-13" src="https://i1.wp.com/petolau.github.io/images/post_8/unnamed-chunk-13-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The interpretability of these results would be difficult. Therefore, model-based time series representations are very effective in this use case (so the typical profiles extraction).</p>
<p>I will show you the usage of one more representation method – <strong>FeaClip</strong>. The <strong>FeaClip</strong> is feature extraction method from a clipping representation. The windowing approach alongside FeaClip is recommended to use for every day of time series. The big advantage is that normalisation is not needed alongside FeaClip method. Let’s use it in our case. The windowing method is also directly implemented in <code>repr_matrix</code> function.</p>
<figure>
<pre><code data-lang="r"><span>data_feaclip</span><span> </span><span>&lt;-</span><span> </span><span>repr_matrix</span><span>(</span><span>elec_load</span><span>,</span><span> </span><span>func</span><span> </span><span>=</span><span> </span><span>repr_feaclip</span><span>,</span><span>
</span><span>windowing</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span> </span><span>win_size</span><span> </span><span>=</span><span> </span><span>48</span><span>)</span><span>
</span><span>dim</span><span>(</span><span>data_feaclip</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1]  50 112</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span>clusterings</span><span> </span><span>&lt;-</span><span> </span><span>lapply</span><span>(</span><span>c</span><span>(</span><span>2</span><span>:</span><span>7</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span>
</span><span>pam</span><span>(</span><span>data_feaclip</span><span>,</span><span> </span><span>x</span><span>))</span><span>
</span><span>DB_values</span><span> </span><span>&lt;-</span><span> </span><span>sapply</span><span>(</span><span>seq_along</span><span>(</span><span>clusterings</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>intCriteria</span><span>(</span><span>data_feaclip</span><span>,</span><span> </span><span>as.integer</span><span>(</span><span>clusterings</span><span>[[</span><span>x</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>c</span><span>(</span><span>&quot;Davies_Bouldin&quot;</span><span>)))</span></code></pre>
</figure>
<p>Let’s plot results of internal evaluation.</p>
<figure>
<pre><code data-lang="r"><span>ggplot</span><span>(</span><span>data.table</span><span>(</span><span>Clusters</span><span> </span><span>=</span><span> </span><span>2</span><span>:</span><span>7</span><span>,</span><span> </span><span>DBindex</span><span> </span><span>=</span><span> </span><span>unlist</span><span>(</span><span>DB_values</span><span>)),</span><span>
</span><span>aes</span><span>(</span><span>Clusters</span><span>,</span><span> </span><span>DBindex</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>3</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-16" src="https://i1.wp.com/petolau.github.io/images/post_8/unnamed-chunk-16-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>We can see that now 2 “elbows” appeared. The biggest change is between 2 and 3 number of clusters, so I will choose number 3.</p>
<figure>
<pre><code data-lang="r"><span># prepare data for plotting</span><span>
</span><span>data_plot</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>data.table</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>as.factor</span><span>(</span><span>clusterings</span><span>[[</span><span>2</span><span>]]</span><span>$</span><span>clustering</span><span>),</span><span>
</span><span>data_feaclip</span><span>)))</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>Time</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>ncol</span><span>(</span><span>data_feaclip</span><span>),</span><span> </span><span>each</span><span> </span><span>=</span><span> </span><span>nrow</span><span>(</span><span>data_feaclip</span><span>))]</span><span>
</span><span>data_plot</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>nrow</span><span>(</span><span>data_feaclip</span><span>),</span><span> </span><span>ncol</span><span>(</span><span>data_feaclip</span><span>))]</span><span>
</span><span># prepare medoids</span><span>
</span><span>centers</span><span> </span><span>&lt;-</span><span> </span><span>data.table</span><span>(</span><span>melt</span><span>(</span><span>clusterings</span><span>[[</span><span>2</span><span>]]</span><span>$</span><span>medoids</span><span>))</span><span>
</span><span>setnames</span><span>(</span><span>centers</span><span>,</span><span> </span><span>c</span><span>(</span><span>&quot;Var1&quot;</span><span>,</span><span> </span><span>&quot;Var2&quot;</span><span>),</span><span> </span><span>c</span><span>(</span><span>&quot;class&quot;</span><span>,</span><span> </span><span>&quot;Time&quot;</span><span>))</span><span>
</span><span>centers</span><span>[,</span><span> </span><span>ID</span><span> </span><span>:=</span><span> </span><span>class</span><span>]</span><span>
</span><span># plot the results</span><span>
</span><span>ggplot</span><span>(</span><span>data_plot</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>,</span><span> </span><span>group</span><span> </span><span>=</span><span> </span><span>ID</span><span>))</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span>class</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>scales</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey10&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.65</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>data</span><span> </span><span>=</span><span> </span><span>centers</span><span>,</span><span> </span><span>aes</span><span>(</span><span>Time</span><span>,</span><span> </span><span>value</span><span>),</span><span>
</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;firebrick1&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.80</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1.2</span><span>)</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;Time&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;Load (normalised)&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme_bw</span><span>()</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-17" src="https://i2.wp.com/petolau.github.io/images/post_8/unnamed-chunk-17-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>It seems like good separability of clusters, better than in the case of DFT.<br>
But you can check also other results of clusterings with the different number of clusters.</p>
<h2>Conclusion</h2>
<p>In this tutorial, I showed you the usage of time series representation methods to create more characteristic profiles of consumers.<br>
Then, time series representations, calculated by <strong>TSrepr</strong> package, were clustered by K-medoids and typical consumption profiles were extracted from created clusters.</p>
<p>Time series representations can be helpful also in other use cases as classification or time series indexing.<br>
You can check how I use time series representations in my dissertation thesis in more detail on the <a rel="nofollow" href="https://petolau.github.io/research" target="_blank"><strong>research</strong> section</a> of this site.</p>
<h2>References</h2>
<p>Laurinec, Peter, and Mária Lucká. 2016. “Comparison of Representations of Time Series for Clustering Smart Meter Data.” In Lecture Notes in Engineering and Computer Science: Proceedings of the World Congress on Engineering and Computer Science 2016, 458–63.</p>
<p>Laurinec, Peter, Marek Lóderer, Petra Vrablecová, Mária Lucká, Viera Rozinajová, and Anna Bou Ezzeddine. 2016. “Adaptive Time Series Forecasting of Energy Consumption Using Optimized Cluster Analysis.” In Data Mining Workshops (Icdmw), 2016 Ieee 16th International Conference on, 398–405. IEEE.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://petolau.github.io/TSrepr-clustering-time-series-representations/"> Peter Laurinec</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/gxbRC0UCea4" height="1"></a></div>