본문 바로가기
개인 프로젝트/시스템트레이딩

[affinity propagation] GraphicalLassoCV 를 이용한 비지도 군집화

by 달죽 2020. 11. 10.
반응형
from matplotlib.collections import LineCollection
from sklearn import cluster, covariance, manifold
import sys
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.font_manager as fm


print(__doc__)

quotes = []

 

import FinanceDataReader as fdr # 주가데이터 불러오는 모듈 

data = pd.read_csv('sector_2020-11-05.csv').iloc[:100].dropna(axis=0)
CODE = data.CODE.tolist()
names = data.CODE_NAME.tolist()

quotes = []
for i in CODE :
    d = fdr.DataReader(i, "20180830", "20201106").reset_index()[['Date','Open','Close']]
    quotes.append(d)
quotes[0].Close

537일 동안의 종가 데이터를 불러온것. 

 

close_prices = np.vstack([q['Close'] for q in quotes])
open_prices = np.vstack([q['Open'] for q in quotes])

# 하루의 변동성을 추출해온다. 
variation = close_prices - open_prices


# #############################################################################

edge_model = covariance.GraphicalLassoCV()

# covariance 를 distance 로 설정하기 위해 이 모델을 불러온다.


# 시계열 정규화 : covariance 공분산보다 correlation 상관계수를 이용하는게 
# 구조를 만들때 더 효과적이다. 

X = variation.copy().T
X = np.array(X,dtype=float)
names = np.array(names)

X.shape
# (538, 82)
X /= X.std(axis=0)
edge_model.fit(X)

# #############################################################################
# affinity propagation 를 이용해 군집화 해보자.

_, labels = cluster.affinity_propagation(edge_model.covariance_,
                                         random_state=0)
n_labels = labels.max()

for i in range(n_labels + 1):
    print('Cluster %i: %s' % ((i + 1), ', '.join(names[labels == i])))

# #############################################################################

# 시각화를 위한 저차원 임베딩 찾기: 2D 평면에서 노드에서의 최상의 위치를 찾습니다

# 우리는 재현성을 달성하기 위해 밀도가 높은  eigen_solver 를 사용한다
# arpack은 우리가 통제하지 않는 무작위 벡터로 시작된다
# 우리는 대규모 구조를 포착하기 위해 많은 이웃을 사용한다.

node_position_model = manifold.LocallyLinearEmbedding(
    n_components=2, eigen_solver='dense', n_neighbors=6)

embedding = node_position_model.fit_transform(X.T).T

# #############################################################################
# 시각화
plt.figure(1, facecolor='w', figsize=(10, 8))
plt.clf()
ax = plt.axes([0., 0., 1., 1.])
plt.axis('off')

# partial correlations 그래프 시각화 
partial_correlations = edge_model.precision_.copy()
d = 1 / np.sqrt(np.diag(partial_correlations))
partial_correlations *= d
partial_correlations *= d[:, np.newaxis]
non_zero = (np.abs(np.triu(partial_correlations, k=1)) > 0.02)

# 임베딩의 좌표를 사용하여 노드를 배치합니다
plt.scatter(embedding[0], embedding[1], s=100 * d ** 2, c=labels,
            cmap=plt.cm.nipy_spectral)

# 가장자리 그래프를 그려줍니다.
start_idx, end_idx = np.where(non_zero)

# (*line0*, *line1*, *line2*)
# linen = (x0, y0), (x1, y1), ... (xm, ym)

segments = [[embedding[:, start], embedding[:, stop]]
            for start, stop in zip(start_idx, end_idx)]
values = np.abs(partial_correlations[non_zero])

lc = LineCollection(segments,
                    zorder=0, cmap=plt.cm.hot_r,
                    norm=plt.Normalize(0, .7 * values.max()))
lc.set_array(values)
lc.set_linewidths(15 * values)
ax.add_collection(lc)


path = 'C:\\Users\\user\\Downloads\\NEXONLv1GothicLight.ttf' # 글자 깨지기 방지 

fontprop = fm.FontProperties(fname=path, size=8) 

# Add a label to each node. The challenge here is that we want to
# position the labels to avoid overlap with other labels
for index, (name, label, (x, y)) in enumerate(
        zip(names, labels, embedding.T)):

    dx = x - embedding[0]
    dx[index] = 1
    dy = y - embedding[1]
    dy[index] = 1
    this_dx = dx[np.argmin(np.abs(dy))]
    this_dy = dy[np.argmin(np.abs(dx))]
    if this_dx > 0:
        horizontalalignment = 'left'
        x = x + .002
    else:
        horizontalalignment = 'right'
        x = x - .002
    if this_dy > 0:
        verticalalignment = 'bottom'
        y = y + .002
    else:
        verticalalignment = 'top'
        y = y - .002
    plt.text(x, y, name, size=12,
             horizontalalignment=horizontalalignment,
             verticalalignment=verticalalignment,
             fontproperties=fontprop,
             bbox=dict(facecolor='w',
                       edgecolor=plt.cm.nipy_spectral(label / float(n_labels)),
                       alpha=.6))

plt.xlim(embedding[0].min() - .15 * embedding[0].ptp(),
         embedding[0].max() + .10 * embedding[0].ptp(),)
plt.ylim(embedding[1].min() - .03 * embedding[1].ptp(),
         embedding[1].max() + .03 * embedding[1].ptp())

plt.show()

2년간의 종목의 종가만으로 어떤 종목들이 서로 주가상관성을 이루고 있는지 군집화를 보여주는 그래프다.

보통 같은 계열사, 같은 업종이 같이 움직이는것을 한눈에 볼수 있다.

K-means 도 시계열의 correlation 을 distance 로 구현해볼수 있는데, k-means 는 군집수를 정해줘야 한다.

 

다음에는 k-means를 이용해서 시계열 데이터를 이용해 군집화를 해보겠다.   

 

 

참고 : CHAPTER 13 시계열 클러스터링 

 

 

 

반응형

댓글