Lab 9: Time Series - Motif Discovery

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import ts_functions as ts

data = pd.read_csv('data/ashrae_single.csv')
index_var = 'timestamp'
variable = 'meter_reading'
data[index_var] = pd.to_datetime(data[index_var])
data = data.set_index(index_var).sort_index()

FIG_WIDTH, FIG_HEIGHT = 3*ts.HEIGHT, ts.HEIGHT/2

plt.figure(figsize=(FIG_WIDTH, FIG_HEIGHT))
ts.plot_series(data, x_label='timestamp', y_label='consumption', title='ASHRAE original')
plt.xticks(rotation = 45)
plt.show()

Matrix Profile

Compute Matrix Profiles

Here we compute Matrix Profiles over varying window sizes:

8 hours Half of a day (12 hours) A day (24 hours) A week (7 days) A month (30 days) A quarter (90 days)

In [2]:
import matrixprofile as mp

all_windows = [
    ('8 Hours', 8),
    ('12 Hours', 12),
    ('Day', 24),
    ('Week', 7 * 24),
    ('Month', 30 * 24),
    ('Quarter', 3 * 30 * 24),
]

def compute_matrix_profiles(df: pd.DataFrame, windows: list) :
    profiles = {}
    for label, size in windows:
        key = '{} Profile'.format(label)
        profiles[key] = mp.compute(df[variable].values, size)
    return profiles

def plot_signal_data(profiles: dict, windows: list):
    _, axes = plt.subplots(len(windows), 1, sharex=True, figsize=(FIG_WIDTH, len(windows)*FIG_HEIGHT))
    for ax_idx, window in enumerate(windows):
        key = '{} Profile'.format(window[0])
        axes[ax_idx].plot(profiles[key]['mp'])
        axes[ax_idx].set_title(key)

    plt.xlabel(index_var)
    plt.tight_layout()
    plt.show()

all_profiles = compute_matrix_profiles(data, all_windows)
plot_signal_data(all_profiles, all_windows)

Motifs

In [3]:
def compute_all_profiles(profiles: dict, windows: list, k: int, type: str='motifs'):
    discover_function = mp.discover.motifs
    if type == 'discords':
        discover_function = mp.discover.discords

    for label, size in windows:
        key = '{} Profile'.format(label)
        profiles[key] = discover_function(profiles[key], k=k, exclusion_zone=2*size//3)

compute_all_profiles(all_profiles, all_windows, k=5, type='motifs')
In [4]:
def show_profile(profile, title, type):
    lst_figs = mp.visualize(profile)
    for i in range(len(lst_figs)-1):
        plt.close(lst_figs[i])
    plt.suptitle(type + ' - ' + title)
    plt.show()

title = all_windows[0][0]+' Profile'
show_profile(all_profiles[title], title, 'Motifs')
In [5]:
title = all_windows[2][0]+' Profile'
show_profile(all_profiles[title], title, 'Motifs')
In [6]:
title = all_windows[3][0]+' Profile'
show_profile(all_profiles[title], title, 'Motifs')
In [7]:
title = all_windows[4][0]+' Profile'
show_profile(all_profiles[title], title, 'Motifs')
In [8]:
title = all_windows[5][0]+' Profile'
show_profile(all_profiles[title], title, 'Motifs')

Discords / Anomalies

In [9]:
compute_all_profiles(all_profiles, all_windows, k=5, type='discords')
In [10]:
title = all_windows[0][0]+' Profile'
show_profile(all_profiles[title], title, 'Discords')
/Users/claudia/Dev/DSlabs/venv/lib/python3.8/site-packages/matrixprofile/visualize.py:375: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  fig.tight_layout()
In [11]:
title = all_windows[3][0]+' Profile'
show_profile(all_profiles[title], title, 'Discords')
/Users/claudia/Dev/DSlabs/venv/lib/python3.8/site-packages/matrixprofile/visualize.py:375: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  fig.tight_layout()