RandomForest를 사용한 주가 예측
RandomForestClassifier
랜덤포레스트의 분류를 기법은 sklearn.ensemble.RandomForestClassifier()
를 사용합니다.
- n_estimators: 앙상블에 사용할 결정 트리의 개수. 일반적으로 클수록 모델의 성능이 향상되지만, 계산 비용도 증가. (기본값: 100)
- criterion: 각 트리의 노드를 분할하는 데 사용할 함수. 'gini' (지니 불순도) 또는 'entropy' (정보 이득)를 사용할 수 있습니다. (기본값: 'gini')
- max_depth: 각 트리의 최대 깊이를 제한합니다. 깊이가 깊어질수록 모델이 복잡해지고 과적합될 가능성이 높아집니다. None으로 설정하면 모든 리프 노드가 순수해질 때까지 또는 모든 리프 노드가 min_samples_split 샘플보다 적은 수의 샘플을 가질 때까지 트리가 확장됩니다. (기본값: None)
- min_samples_split: 노드를 분할하는 데 필요한 최소 샘플 수입니다. 이 값보다 적은 샘플을 가진 노드는 더 이상 분할되지 않습니다. (기본값: 2)
- min_samples_leaf: 리프 노드가 가져야 하는 최소 샘플 수입니다. 이 값보다 적은 샘플을 가진 리프 노드는 생성되지 않습니다. (기본값: 1)
- max_features: 각 노드에서 분할을 위해 고려할 특성의 최대 개수입니다.
- 'sqrt' (또는 'log2'): sqrt(n_features) 개의 특성을 사용합니다.
- 'log2': log2(n_features) 개의 특성을 사용합니다.
- None (또는 'auto'): 모든 특성을 사용합니다.
- 정수 값: 지정된 개수의 특성을 사용합니다.
- 부동 소수점 값 (0.0 ~ 1.0): 전체 특성 수의 해당 비율만큼 사용합니다. (기본값: 'sqrt')
- bootstrap: 각 트리를 학습할 때 부트스트랩 샘플링을 사용할지 여부입니다. True이면 사용하고, False이면 전체 훈련 데이터셋을 사용합니다. (기본값: True)
- bootstrap Sampling: 원본 데이터에서 중복을 허용하며 랜덤하게 일부 샘플을 선택하는 기법
- oob_score: OOB (Out-of-Bag) 샘플을 사용하여 모델의 일반화 성능을 추정할지 여부입니다. True로 설정하면 학습 완료 후 OOB 점수가 계산됩니다. (기본값: False)
- OOB(Out of Bag): 부트스트랩 샘플링에서 일부 데이터 포인트는 특정 결정트리에서의 학습에 포함시키지 않습니다. 이러한 샘플을 OOB 샘플이라 합니다. 이 샘플은 모델 검증에 사용되므로 학습데이터와 검증데이터의 분리가 일어나고 모델의 일반화(과적합 방지) 성능을 높이는데 도움이 됩니다.
- n_jobs: 모델 학습 및 예측에 사용할 병렬 처리 코어 수입니다. -1로 설정하면 모든 가용 코어를 사용합니다. (기본값: None, 즉 1개의 코어 사용)
- random_state: 난수 발생 시드를 설정하여 결과의 재현성을 확보합니다. (기본값: None)
- class_weight: 훈련 데이터의 클래스에 가중치를 부여하는 데 사용됩니다. 불균형한 클래스 문제를 처리하는 데 유용합니다. 'balanced' 또는 딕셔너리 형태로 가중치를 지정할 수 있습니다. (기본값: None)
주요 메서드
- fit(X, y): 훈련 데이터 X와 타겟 변수 y를 사용하여 모델을 학습합니다.
- predict(X): 학습된 모델을 사용하여 새로운 데이터 X의 클래스를 예측합니다.
- predict_proba(X): 각 샘플이 각 클래스에 속할 확률을 반환합니다.
- score(X, y): 주어진 테스트 데이터 X와 타겟 변수 y에 대한 모델의 정확도를 반환합니다.
- get_params([deep]): 모델의 파라미터를 딕셔너리 형태로 반환합니다.
- set_params(**params): 모델의 파라미터를 설정합니다.
- feature_importances_: 학습 후 각 특성의 중요도를 배열 형태로 반환합니다. 값이 클수록 해당 특성이 분류에 더 중요한 역할을 했다는 것을 의미합니다.
- oob_score_: oob_score=True로 설정했을 때 계산되는 OOB 점수를 반환합니다.
- oob_decision_function_: oob_score=True로 설정했을 때 각 훈련 샘플에 대한 OOB 예측의 결정 함수 결과를 반환합니다.
import numpy as np import pandas as pd import pandas_ta as ta import matplotlib.pyplot as plt import FinanceDataReader as fdr import matplotlib.pyplot as plt from sklearn.model_selection import GridSearchCV from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor from sklearn.model_selection import GridSearchCV from sklearn.preprocessing import StandardScaler, MinMaxScaler from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, mean_squared_error, r2_score st=pd.Timestamp(2020, 1,1) et=pd.Timestamp(2025, 5,16) trgnme="000660" trg=fdr.DataReader(trgnme, st, et) df=trg[["Open", "High", "Low", "Close", "Volume"]] df.tail(1)
Open | High | Low | Close | Volume | |
---|---|---|---|---|---|
Date | |||||
2025-05-16 | 206000 | 206750 | 203500 | 204500 | 2419507 |
분류를 위해 Close 자료를 대상으로 시차 1을 기준으로 증가(1), 감소(-1)를 계산한 결과를 반응변수로 합니다. 나머지 설명변수를 표준화합니다.
scaler=StandardScaler().fit(df) X_T=scaler.transform(df) X=X_T[:-1,:] y=np.where(df["Close"]-df["Open"]>0, 1, -1)[1:] y[:3]
array([-1, 1, -1])
학습과 검증 데이터를 분류하고 RandomForestClassifier()을 사용하여 분류 모델을 설정합니다. 이 함수에는 다양한 하이퍼변수가 필요하며 적절한 변수를 선정하기 위해 GridSearchCV() 함수를 사용합니다.
param_grid={'n_estimators': [5, 10, 15, 20], "max_depth":[5, 10, 20, None]} rfc_search=GridSearchCV(RandomForestClassifier(random_state=3), param_grid, cv=5, scoring="accuracy") rfc_search.fit(Xtr, ytr) rfc_search.best_estimator_
RandomForestClassifier(max_depth=5, n_estimators=10, random_state=3)
rfc_search.score(Xtr, ytr), rfc_search.score(Xte, yte)
(0.6847237269772481, 0.5176767676767676)
rfc_search.predict(X_T[-1,:].reshape(-1, 5))
array([-1])
RandomForestRegressor
randomforestregression()은 다수의 결정트리(회귀모델)을 기반으로하는 앙상블 학습방법입니다. 다수의 회귀모델에서 각각의 예측을 수행하고 그 평균값을 최종 예측값으로 합니다. 이로인해 데이터의 일부와 무작위로 선택된 특징(설명변수)을 사용하여 트리(회귀모델)를 학습하기 때문에 과적합 위험을 감소시킵니다. 또한 결정 트리를 기반으로 하므로 데이터 내의 복잡한 비선형 관계 모델링에 적합합니다.
sklearn.ensemble.RandomForestRegressor() 클래스를 사용합니다.
- n-estimators: 트리(모델)의 개수, 많을수록 성능향상 그러나 계산비용 증가 , 기본값=100
- criterion: 각 트리의 노드를 분할하는 사용할 손실함수, 회귀에는 'squared_error'(기본값), 'absolute_error'를 사용
- max_depth: 각 결정 트리의 최대 깊이. 깊어지면 모델의 복잡도 상승으로 과적합의 위험 증가. None(기본값)로 설정하면 min_samples_split보다 작은 샘플 수를 가질 때까지 분할
- min_samples_split: 노드 분할을 위한 최소 샘플 수, 기본값 = 2
- min_sampels_leaf: leaf 노드가 가져야 하는 최소 샘플 수 , 기본값=1
- max_features: 각 노드에서 최적의 분할을 찾을 때 고려할 특징의 최대개수.
- $\text{sqrt or auto}= \sqrt{\text{# of features}} $
- 'log2': log2 만큼의 특징을 사용
- [0, 1]사이의 실수를 지정하면 전체 특징의 수에 대한 비율을 사용
- None or 1.0(기본값): 모든 특징의 수
- max_samples: 각 트리에서 훈련 데이터의 비울 또는 개수.
- random_state
- n_jobs: 사용될 CPU 코어수. -1로 설정시 모든 코어를 사용
특정한 열을 반응변수, 나머지를 설명변수로 하고 설명과 반응변수의 시차를 1로 합니다. 설명과 반응변수를 표준화합니다. 설명변수의 마지막행을 최종 예측변수로 사용합니다.
ind=df.drop(labels=["Close"], axis=1).values de=df["Close"].values scalerX=StandardScaler().fit(ind[:-1, :]) X=scalerX.transform(ind[:-1,:]) Xfinal=scalerX.transform(ind[-1,:].reshape(-1, 4)) scalery=StandardScaler() y=scalery.fit_transform(de[1:].reshape(-1,1)).flatten() Xfinal
array([[ 2.04934765, 1.98281255, 2.07244882, -0.82600277]])
GridSearchCV() 함수를 사용하여 적정한 하이퍼매개변수를 설정하여 적절한 모델을 생성할 수 있습니다.
Xtr, Xte, ytr, yte=train_test_split(X, y, test_size=0.3, random_state=3) reg_param_grid={'n_estimators': [10, 30, 60, 100, 120]} reg_search=GridSearchCV(RandomForestRegressor(random_state=3), param_grid, cv=5, scoring="neg_mean_squared_error") reg_search.fit(Xtr, ytr) reg_search.best_estimator_
RandomForestRegressor(max_depth=5, n_estimators=20, random_state=3)
다음은 메서드 score()를 사용한 것으로 결과는 음의 평균 제곱오차(NMSE)입니다.
reg_search.score(Xtr, ytr), reg_search.score(Xte, yte)
(-0.006295633740480161, -0.011518694438607695)
위 모델에 대한 학습과 검증 데이터의 R2를 확인해 봅니다.
pred_tr=reg_search.predict(Xtr) r2_score(ytr, pred_tr)
0.9935957464751347
pred_te=reg_search.predict(Xte) r2_score(yte, pred_te)
0.9888857334889395
최종예측인자에 의한 예측
pre_final=reg_search.predict(Xfinal) scalery.inverse_transform(pre_final.reshape(-1,1))
array([[202123.26656103]])
주가 예측은 Open, High, Low, Close의 모든 변수에 대해 이루어져야 합니다. 이를 위해 위 과정을 하나의 함수로 작성합니다.
def rfrPredict(df, deCol="Close", testSize=0.3, randomState=7): ind=df.drop(labels=deCol, axis=1).values de=df[deCol].values scalerX=StandardScaler().fit(ind[:-1, :]) X=scalerX.transform(ind[:-1,:]) Xfinal=scalerX.transform(ind[-1,:].reshape(-1, ind.shape[1])) scalery=StandardScaler() y=scalery.fit_transform(de[1:].reshape(-1,1)).flatten() Xtr, Xte, ytr, yte=train_test_split(X, y, test_size=testSize, random_state=randomState) reg_param_grid={'n_estimators': [10, 30, 60, 100, 120]} reg_search=GridSearchCV(RandomForestRegressor(random_state=randomState), reg_param_grid, cv=5, scoring="neg_mean_squared_error") reg_search.fit(Xtr, ytr) pre_final=reg_search.predict(Xfinal) pre=scalery.inverse_transform(pre_final.reshape(-1,1)).flatten() return pre
위 함수를 사용하여 위 데이터 df에 대해 시가, 고가, 저가, 종가의 최종예측은 다음과 같습니다.
result={} for i in ["Open","High","Low", "Close"]: result[i]=rfrPredict(df, deCol=i) result=pd.DataFrame(result) result
Open | High | Low | Close | |
---|---|---|---|---|
0 | 207124.48211 | 206800.0 | 201173.869794 | 202123.266561 |
df에 기술적 지표 macd, adx, rsi를 적용하여 직전과 같은 예측치를 계산합니다.
data=trg.copy() data["macd"]=data.ta.macd(fast=5, slow=20, signal=9).iloc[:,0] data["adx"]=data.ta.adx().iloc[:,0] data["rsi"]=data.ta.rsi() data=data.dropna() data.head(1)
Open | High | Low | Close | Volume | Change | macd | adx | rsi | |
---|---|---|---|---|---|---|---|---|---|
Date | |||||||||
2020-02-12 | 100500 | 101000 | 99100 | 100000 | 2616573 | 0.002004 | 1067.067403 | 13.611534 | 59.511464 |
result2={} for i in ["Open","High","Low", "Close"]: result2[i]=rfrPredict(data, deCol=i) result2=pd.DataFrame(result2) result2.round(0)
0 | 207976.0 | 209795.0 | 201843.0 | 205168.0 |
---|
위 결과에 당일의 시가를 적용하여 고가, 저가, 종가를 예측합니다.
result2-(result2.values[0,0]-203000)
0 | 203000.0 | 204819.666667 | 196867.5 | 200192.5 |
---|
댓글
댓글 쓰기