네이버 주식 서비스로부터 종목 시가, 종가, 고가, 저가, 거래량, 전일대비에 대한 시계열 데이터 얻기

주식 종목에 대한 하루 단위의 시가, 종가, 거래량 등을 웹을 통해 얻을 수 있는데요. 이러한 데이터를 파이썬을 이용해, 네이버의 주식 서비스로부터 얻는 코드에 대해 설명합니다.

코드는 다음과 같습니다. 원하는 종목에 대해 원하는 페이지만큼.. (이 부분은 주식 서비스마다 가능 여부 및 방식이 달라짐) 정보를 얻어옵니다.

import requests
from bs4 import BeautifulSoup

def print_stock_price(code, page_num):
    result = [[], [], [], [], [], [], [], [], []]

    for n in range(page_num):
        url = 'https://finance.naver.com/item/sise_day.nhn?code='+code+'&page='+str(n+1)
        print(url)

        r = requests.get(url)

        if not r.ok: 
            print('Not more data !')
            break

        html = r.content
        soup = BeautifulSoup(html, 'html.parser')
        tr = soup.select('table > tr')

        for i in range(1, len(tr)-1):
            td = tr[i].select('td')
            if td[0].text.strip():
                result[0].append(td[0].text.strip()) # 날짜
                result[1].append(td[1].text.strip()) # 종가
                
                img = td[2].select('img')
                if len(img) != 0: 
                    if 'src' in img[0].attrs:
                        src = img[0]['src']
                        if 'up' in src: result[2].append('상승')
                        else: result[2].append('하락')
                else: result[2].append('보합')

                result[3].append(td[2].text.strip()) # 전일대비
                result[4].append(td[3].text.strip()) # 시장가
                result[5].append(td[4].text.strip()) # 최고가
                result[6].append(td[5].text.strip()) # 최저가
                result[7].append(td[6].text.strip()) # 거래량

    for i in range(len(result[0])):
        #     날짜          종가           상승/하락/보합+a           시장가         최고가        최저가        거래량
        print(result[0][i], result[1][i], result[2][i]+result[3][i], result[4][i], result[5][i], result[6][i], result[7][i])

print_stock_price(code='005930', page_num=1)

코드를 보면, print_stock_price 함수의 url 변수에 저장된 주소에 대한 결과 DOM을 해석하고 있는 것을 알 수 있습니다. 즉, DOM에 대한 구조를 먼저 파악해야 한다는 것이 핵심인데요. 위의 코드가 정상적으로 작동할 당시의 실제 DOM의 한가지 예는 다음과 같습니다.

코드와 추출하고자 하는 DOM 요소가 명확하게 1:1로 매칭되고 있는 것을 확인할 수 있습니다.

scikit-learn의 SVM을 통한 분류(Classification)

SVM(Support Vector Machine)은 데이터 분석 중 분류에 이용되며 지도학습 방식의 모델입니다. SVM에 대한 좋은 구현체는 사이킷-런(scikit-learn)인데, 이를 이용해 SVM에 대한 내용을 정리해 봅니다.

먼저 학습을 위한 입력 데이터가 필요한데, scikit-learn은 데이터 분류를 목적으로 데이터를 생성해 주는 make_blobs라는 함수를 제공합니다. 이를 이용해 아래처럼 2종류의 총 40개의 샘플 데이터를 생성합니다.

import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets.samples_generator import make_blobs

X, y = make_blobs(n_samples=40, centers=2, random_state=20)

위에서 생성한 데이터 샘플을 SVM으로 학습시키는 코드는 다음과 같습니다.

clf = svm.SVC(kernel='linear')
clf.fit(X, y)

SVM은 선형 분류와 비선형 분류를 지원하는데, 그 중 선형 모델을 위해 kernel을 linear로 지정하였습니다. 비선형에 대한 kernel로는 rbf와 poly 등이 있습니다.

학습된 SVM 모델을 통해 데이터 (3,4)를 분류하는 코드는 다음과 같습니다.

newData = [[3,4]]
print(clf.predict(newData))

다음은 시각화입니다. 샘플 데이터와 초평면(Hyper-Plane), 지지벡터(Support Vector)를 그래프에 표시하는 코드는 다음과 같습니다.

# 샘플 데이터 표현
plt.scatter(X[:,0], X[:,1], c=y, s=30, cmap=plt.cm.Paired)

# 초평면(Hyper-Plane) 표현
ax = plt.gca()

xlim = ax.get_xlim()
ylim = ax.get_ylim()

xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = clf.decision_function(xy).reshape(XX.shape)

ax.contour(XX, YY, Z, colors='k', levels=[-1,0,1], alpha=0.5, linestyles=['--', '-', '--'])

# 지지벡터(Support Vector) 표현
ax.scatter(clf.support_vectors_[:,0], clf.support_vectors_[:,1], s=60, facecolors='r')

plt.show()

결과는 다음과 같습니다. 빨간색 포인트가 지지벡터이고, 진한 회색선이 초명편입니다.

다음은 비선형 SVM로써 kernel이 rbf인 결과 그래프입니다.

[Python] 알파벳을 인덱스로 구성하기

먼저 다음과 같은 문장이 있다고 하자.

sample = 'I will go.'

위의 문장을 구성하는 알파벳 중에서 중복되지 않는 고유한 알파벳만을 추출하면..

uniq_chars = set(sample) # {'w', ' ', 'o', 'i', 'l', '.', 'g', 'I'}

위의 추출된 결과는 set이므로 이를 list로 만들면..

idx2char = list(uniq_chars) # ['w', ' ', 'o', 'i', 'l', '.', 'g', 'I']

인덱스 값을 Value로, 해당 인덱스의 알파벳을 Key로 구성된 데이터는 다음처럼 얻을 수 있다.

char2idx = {c: i for i, c in enumerate(idx2char)} # {'w': 0, ' ': 1, 'o': 2, 'i': 3, 'l': 4, '.': 5, 'g': 6, 'I': 7}

이제 처음 문장(sample 변수)을 인덱스 값으로 구성된 list는 다음과 같다.

sample_idx = [char2idx[c] for c in sample] # [7, 1, 0, 3, 4, 4, 1, 6, 2, 5]

Numpy의 axis에 따른 연산

넘파이의 sum 함수를 예로 axis의 값에 따라 어떻게 연산이 처리되는지를 시각화해 본다.

먼저 x는 다음과 같다.

x = np.array([
    [ 1,  2,  3,  4],
    [ 5,  6,  7,  8],
    [ 9, 10, 11, 12],
])

위의 x를 행렬로 시각화 하면 다음과 같다.

이 x에 대한 axis=0으로 한 sum 함수에 대한 코드는 다음과 같으며 그 결과는 바로 다음의 그림과 같다.

np.sum(x, axis=0)

이 x에 대한 axis=1으로 한 sum 함수에 대한 코드는 다음과 같으며 그 결과는 바로 다음의 그림과 같다.

np.sum(x, axis=1)