時系列クラスタリング

# 時系列クラスタリング
#### 時系列クラスタリングは、時系の経過に伴って変化するデータを分析し、類似したパターンやトレンドを持つデータポイントを同じクラスタにまとめる手法です。コレにより、データの潜在的な構造やパターンを抽出することができます。

今回はPridict-Feature-Salesのデータを用いて、shop_idを時系列クラスタリングをしてみました。

### ライブラリ&データの読み込み
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings
from tslearn.clustering import TimeSeriesKMeans
from tslearn.utils import to_time_series_dataset
from tslearn.preprocessing import TimeSeriesScalerMeanVariance

plt.rcParams['font.family'] = 'Hiragino Maru Gothic Pro'
warnings.filterwarnings('ignore')

train = pd.read_csv('sales_train.csv')
```
## 原系列の可視化
### 簡単な前処理&月ごとの集計
```python
train = train[train.item_cnt_day > 0]
print(train.shop_id.unique())
grouped = train[['date_block_num', 'shop_id', 'item_cnt_day']].groupby(['date_block_num', 'shop_id']).sum().reset_index()
grouped = grouped.pivot('shop_id', 'date_block_num', 'item_cnt_day').fillna(0)
grouped.head()
```
![スクリーンショット 2023-12-18 0.14.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536819/e59deef8-d101-612e-7dde-067ccfa81b98.png)

### 時系列データセット型にする&時系列の可視化
```python
time_np = to_time_series_dataset(grouped)

fig, ax = plt.subplots(figsize=(20,8))

for i, x in enumerate(time_np[:]):
    ax.plot(x, label='shop'+str(i))

ax.legend(loc='upper left', bbox_to_anchor=(1.05, 1))
plt.show()
```
![スクリーンショット 2023-12-18 0.16.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536819/d97e557b-2d0e-847b-4549-7f486e8058dd.png)

### エルボー法で最適なクラスタを見つける
```python
inertia = []
for n_clusters in range(1,12):
    km = TimeSeriesKMeans(n_clusters=n_clusters, metric='euclidean', random_state=0)
    km.fit(time_np)
    inertia.append(km.inertia_)

plt.figure(figsize=(10, 6))
plt.plot(range(1,12), inertia, marker='o')
plt.xlabel('クラスタ数')
plt.ylabel('SSE')
plt.title('エルボー法')
plt.show()
```
![スクリーンショット 2023-12-18 9.23.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536819/91259b4a-89fb-c0df-bc7f-1002df029396.png)


### クラスタごとに表示
```python
n = 4
km_euclidean = TimeSeriesKMeans(n_clusters=n, metric='euclidean', random_state=0)
labels_euclidean = km_euclidean.fit_predict(time_np)
print(labels_euclidean)

fig, axes = plt.subplots(n, figsize=(8,16))
plt.subplots_adjust(hspace=0.5)
for i in range(n):
    ax = axes[i]

    for x in time_np[labels_euclidean == i]:
        ax.plot(x.ravel(), 'k-', alpha=0.2)
    ax.plot(km_euclidean.cluster_centers_[i].ravel(), 'r-')

    datanum = np.count_nonzero(labels_euclidean == i)
    ax.text(0.5, (0.7+0.25), f'Cluster{(i)} : n = {datanum}')
    if i == 0:
        ax.set_title('時系列クラスタリング')
plt.show()
#出力
#[2 2 2 2 0 0 3 0 2 2 2 2 0 2 0 0 0 2 0 0 2 0 0 2 0 1 0 3 1 0 0 1 2 2 2 0 2
# 0 0 2 2 0 3 0 0 0 0 0 2 2 0 0 0 0 1 0 0 3 0 0]
```
![スクリーンショット 2023-12-18 9.30.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536819/370f9bac-edfb-0b63-374f-d95c69afc34a.png)
![スクリーンショット 2023-12-18 9.31.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536819/47ff0038-2466-3d0f-61e1-fe03a6ba9b67.png)
### 全クラスタを表示
```python
n = 4
km_euclidean = TimeSeriesKMeans(n_clusters=n, metric='euclidean', random_state=0)
labels_euclidean = km_euclidean.fit_predict(grouped)
print(labels_euclidean)

colors = pd.DataFrame(labels_euclidean).replace({0:'r', 1:'b', 2:'g', 3:'black'})

fig = plt.figure(figsize=(20,8))
index = 0
for shop in grouped.T.columns:
    plt.plot(grouped.T.index, grouped.T[shop], label='shop'+str(shop)+'cluster'+str(labels_euclidean[index]), color=colors[0][index])
    index += 1
plt.legend(loc='upper left', bbox_to_anchor=(1.05, 1))
plt.title('時系列クラスタリング')
plt.show()
#[2 2 2 2 0 0 3 0 2 2 2 2 0 2 0 0 0 2 0 0 2 0 0 2 0 1 0 3 1 0 0 1 2 2 2 0 2
# 0 0 2 2 0 3 0 0 0 0 0 2 2 0 0 0 0 1 0 0 3 0 0]
```
![スクリーンショット 2023-12-18 9.40.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536819/191da227-921a-d41e-e5c9-e583d4a55d95.png)
## 最後に
この記事をいいねボタンをおしてください、ぜひよろしくお願いします。
いいねボタンで、標準化したデータ可視化をしたいと思います。