기본 콘텐츠로 건너뛰기

[ML] 결정트리(Decision Tree) 모델

연속형변수를 목록형변수로 변환

내용

연속형변수를 목록형변수로 변환

연속형 변수인 주가자료를 종가의 상승과 하락에 대한 추정을 위해 로지스틱 회계분석을 적용할 수 있습니다. 이 분석의 자료는 목록변수이어야 하므로 연속형변수를 목록변수로의 전환이 필요합니다. 이번 포스트에서는 이 과정을 소개합니다.

주가자료의 호출과 정리

파이썬 패키지 FinanceDataReader를 사용하여 다양한 금융자료를 사용할 수 있습니다. 다음은 일정 기간의 코스피 자료를 호출한 것입니다.

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import FinanceDataReader as fdr
st=pd.Timestamp(2010,8, 26)
et=pd.Timestamp(2022, 5, 27)
data=fdr.DataReader('KS11', st, et)
data.head(2)
Close Open High Low Volume Change
Date
2010-08-261729.76 1744.08 1744.40 1729.76 303050000.0 -0.0029
2010-08-271729.56 1724.00 1732.84 1719.20 245580000.0 -0.0001

호출받은 자료에 0, Na, inf 등 다양한 종류의 결측치가 포함되어 있을 수 있습니다. 이들은 직전 또는 직후 값으로 대체 또는 삭제 할 수 있습니다. 위에서 사용한 모듈로 부터 호출한 자료는 결측치를 0으로 대체하고 있습니다. 다음은 자료의 값이 0인 행과 열을 반환한 것입니다.

np.where(data==0)
(array([ 450,  473,  541,  571,  643,  689,  831,  904, 1060, 1118, 1273,
        2005, 2081, 2125, 2150, 2376]),
 array([5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]))

인덱스 적용

data에서 0이 아닌 부분만을 추출할 경우 자료의 크기는 변함이 없습니다. 또한 0인 부분도 발견되지 않습니다.

data1=data[data != 0]
data1.shape
(2899, 6)
np.where(data1==0)
(array([], dtype=int64), array([], dtype=int64))

data에서 0인 인덱스의 data1과 비교해보면 0이 nan로 전환됨을 알 수 있습니다.

data.iloc[450, 5], data1.iloc[450, 5]
(0.0, nan)

nan을 제거하기 위해 DataFrame.dropna() 메서드를 사용합니다. 이 결과 자료의 크기는 정확히 data에서 0이 포함된 부분이 제거되었음을 알 수 있습니다.

data2=data1.dropna()
data2.shape
(2883, 6)

.mask()와 .where() 적용

DataFrame.mask(condition, other=nan)메서드를 적용하여 0을 지정한 값으로 전환할 수 있습니다. 이 메서드는 condition=True일 경우 other로 전환됩니다. 이 메서드와 반대는 DataFrame.where(condition, other)로서 condition=True인 경우는 원래값을 유지하고 아닌 경우 other로 전환합니다.

x=pd.DataFrame(np.random.randint(0, 10, (3, 5)))
x
0 1 2 3 4
06 5 5 8 2
18 0 8 5 6
22 1 6 6 8
x.where(x==0, np.nan)
0 1 2 3 4
0NaN NaN NaN NaN NaN
1NaN 0.0 NaN NaN NaN
2NaN NaN NaN NaN NaN
x.where(x!=0)
0 1 2 3 4
06 5.0 5 8 2
18 NaN 8 5 6
22 1.0 6 6 8
x.mask(x==0)
0 1 2 3 4
06 5.0 5 8 2
18 NaN 8 5 6
22 1.0 6 6 8

메서드 mask를 사용하여 객체 data이 값 0을 nan으로 변환합니다. 그 결과는 위에서 인덱스를 사용하여 변환한 결과와 같습니다.

data1=data.mask(data==0)
data1.iloc[449:452, :]
Close Open High Low Volume Change
Date
2012-06-18 1891.71 1892.91 1901.11 1887.05 376280000.0 0.0181
2012-06-19 1891.77 1885.56 1895.32 1883.56 380910000.0 NaN
2012-06-20 1904.12 1908.19 1908.19 1895.27 367740000.0 0.0065

결측값 치환

nan을 제거하기 위해 위에서와 같이 DataFrame.dropna() 메서드를 적용하면 Nan이 포함된 행을 제거한 결과를 반환합니다. 대신에 DataFrame.ffill() 또는 DataFrame.bfill() 메서드를 적용하여 직전 행의 값, 또는 진후 행의 값으로 대체할 수 있습니다.

data1.ffill().iloc[449:452, :]
Close Open High Low Volume Change
Date
2012-06-18 1891.71 1892.91 1901.11 1887.05 376280000.0 0.0181
2012-06-19 1891.77 1885.56 1895.32 1883.56 380910000.0 0.0181
2012-06-20 1904.12 1908.19 1908.19 1895.27 367740000.0 0.0065
data1.bfill().iloc[449:452, :]
Close Open High Low Volume Change
Date
2012-06-18 1891.71 1892.91 1901.11 1887.05 376280000.0 0.0181
2012-06-19 1891.77 1885.56 1895.32 1883.56 380910000.0 0.0065
2012-06-20 1904.12 1908.19 1908.19 1895.27 367740000.0 0.0065

위 두 메서드에 의한 nan의 치환은 DataFrame.fillna(value, method) 메서드로 대신할 수 있습니다. 이 메서드는 nan을 지정한 값(value)나 방법(mehod)으로 치환합니다. 여기서 method는 'bfill'과 'ffill'를 인수로 전달할 수 있으며 결과는 각각 DataFrame.bfill()와 DataFrame.ffill()와 같습니다.

data1.fillna(method="ffill").iloc[449:452, :]
Close Open High Low Volume Change
Date
2012-06-18 1891.71 1892.91 1901.11 1887.05 376280000.0 0.0181
2012-06-19 1891.77 1885.56 1895.32 1883.56 380910000.0 0.0181
2012-06-20 1904.12 1908.19 1908.19 1895.27 367740000.0 0.0065
data1.fillna(method="bfill").iloc[449:452, :]
Close Open High Low Volume Change
Date
2012-06-18 1891.71 1892.91 1901.11 1887.05 376280000.0 0.0181
2012-06-19 1891.77 1885.56 1895.32 1883.56 380910000.0 0.0065
2012-06-20 1904.12 1908.19 1908.19 1895.27 367740000.0 0.0065

변화량 계산과 표준화

목록변수로 전환하기 위해 Close, Open, High, Low, Volume, Change의 각 변수별로 2일간의 변화량을 계산하여 적용합니다. DataFrame.pct_change() 메서드를 적용합니다.

d=data2.pct_change().dropna()
d.head(2)
Close Open High Low Volume Change
Date
2010-08-27-0.000116 -0.011513 -0.006627 -0.006105 -0.189639 -0.965517
2010-08-300.017675 0.014513 0.015876 0.015711 0.007248 -178.000000

전환결과의 데이터들은 변수별로 scale의 차이가 존재합니다. 이는 통계 분석에 큰 분산의 원인이며 모델의 정확도에 손상을 줍니다. 이 부분은 데이터의 표준화로 보상이 됩니다.

from sklearn.preprocessing import StandardScaler
XScaler=StandardScaler().fit(d.values)
Xn=XScaler.transform(d.values)
Xn[:10]
array([[-3.03562817e-02, -1.10544148e+00, -8.04888824e-01,
        -6.28245191e-01, -4.19690250e-02,  2.24060138e-02],
       [ 1.68248655e+00,  1.35086115e+00,  1.85616377e+00,
         1.54718341e+00, -3.70464378e-02, -1.51836969e+01],
         ⋮

목록화

위 결과를 목록화하기 위해 각 값을 일정한 구간별로 분류합니다. 이 과정은 pd.cut()또는 pd.qcut() 함수를 사용할 수 있습니다. cut() 함수는 분류 구간의 상한값과 하한값을 지정하는데 반해 qcut()는 분류구간의 갯수를 지정합니다. 그러므로 qcut()에 의한 분류는 각 소그룹의 크기가 같습니다. 또한 이 두 함수에 대상 자료는 Series로서 1차원 벡터이어야 합니다. 즉, 하나의 열 또는 행에 대해서만 적용할 수 있습니다. 다음과 같이 for 문을 적용합니다.

d2={}
for i in range(Xn.shape[1]):
    d2[i]=pd.qcut(pd.Series(Xn[:,i]), q=10, labels=range(1, 11))
d2=pd.DataFrame(d2.values()).T
d2.columns=d.columns
d2.head(2)
Close Open High Low Volume Change
05 1 2 3 2 6
110 10 10 10 6 1

댓글

이 블로그의 인기 게시물

[Linear Algebra] 유사변환(Similarity transformation)

유사변환(Similarity transformation) n×n 차원의 정방 행렬 A, B 그리고 가역 행렬 P 사이에 식 1의 관계가 성립하면 행렬 A와 B는 유사행렬(similarity matrix)이 되며 행렬 A를 가역행렬 P와 B로 분해하는 것을 유사 변환(similarity transformation) 이라고 합니다. $$\tag{1} A = PBP^{-1} \Leftrightarrow P^{-1}AP = B $$ 식 2는 식 1의 양변에 B의 고유값을 고려한 것입니다. \begin{align}\tag{식 2} B - \lambda I &= P^{-1}AP – \lambda P^{-1}P\\ &= P^{-1}(AP – \lambda P)\\ &= P^{-1}(A - \lambda I)P \end{align} 식 2의 행렬식은 식 3과 같이 정리됩니다. \begin{align} &\begin{aligned}\textsf{det}(B - \lambda I ) & = \textsf{det}(P^{-1}(AP – \lambda P))\\ &= \textsf{det}(P^{-1}) \textsf{det}((A – \lambda I)) \textsf{det}(P)\\ &= \textsf{det}(P^{-1}) \textsf{det}(P) \textsf{det}((A – \lambda I))\\ &= \textsf{det}(A – \lambda I)\end{aligned}\\ &\begin{aligned}\because \; \textsf{det}(P^{-1}) \textsf{det}(P) &= \textsf{det}(P^{-1}P)\\ &= \textsf{det}(I)\end{aligned}\end{align} 유사행렬의 특성 유사행렬인 두 정방행렬 A와 B는 'A ~ B' 와 같

[matplotlib] 히스토그램(Histogram)

히스토그램(Histogram) 히스토그램은 확률분포의 그래픽적인 표현이며 막대그래프의 종류입니다. 이 그래프가 확률분포와 관계가 있으므로 통계적 요소를 나타내기 위해 많이 사용됩니다. plt.hist(X, bins=10)함수를 사용합니다. x=np.random.randn(1000) plt.hist(x, 10) plt.show() 위 그래프의 y축은 각 구간에 해당하는 갯수이다. 빈도수 대신 확률밀도를 나타내기 위해서는 위 함수의 매개변수 normed=True로 조정하여 나타낼 수 있다. 또한 매개변수 bins의 인수를 숫자로 전달할 수 있지만 리스트 객체로 지정할 수 있다. 막대그래프의 경우와 마찬가지로 각 막대의 폭은 매개변수 width에 의해 조정된다. y=np.linspace(min(x)-1, max(x)+1, 10) y array([-4.48810153, -3.54351935, -2.59893717, -1.65435499, -0.70977282, 0.23480936, 1.17939154, 2.12397372, 3.0685559 , 4.01313807]) plt.hist(x, y, normed=True) plt.show()

R 미분과 적분

내용 expression 미분 2차 미분 mosaic를 사용한 미분 적분 미분과 적분 R에서의 미분과 적분 함수는 expression()함수에 의해 생성된 표현식을 대상으로 합니다. expression expression(문자, 또는 식) 이 표현식의 평가는 eval() 함수에 의해 실행됩니다. > ex1<-expression(1+0:9) > ex1 expression(1 + 0:9) > eval(ex1) [1] 1 2 3 4 5 6 7 8 9 10 > ex2<-expression(u, 2, u+0:9) > ex2 expression(u, 2, u + 0:9) > ex2[1] expression(u) > ex2[2] expression(2) > ex2[3] expression(u + 0:9) > u<-0.9 > eval(ex2[3]) [1] 0.9 1.9 2.9 3.9 4.9 5.9 6.9 7.9 8.9 9.9 미분 D(표현식, 미분 변수) 함수로 미분을 실행합니다. 이 함수의 표현식은 expression() 함수로 생성된 객체이며 미분 변수는 다음 식의 분모의 변수를 의미합니다. $$\frac{d}{d \text{변수}}\text{표현식}$$ 이 함수는 어떤 함수의 미분의 결과를 표현식으로 반환합니다. > D(expression(2*x^3), "x") 2 * (3 * x^2) > eq<-expression(log(x)) > eq expression(log(x)) > D(eq, "x") 1/x > eq2<-expression(a/(1+b*exp(-d*x))); eq2 expression(a/(1 + b * exp(-d * x))) > D(eq2, "x") a * (b * (exp(-d * x) * d))/(1 + b