아이티윌_데이터 분석 55기/강의내용 필기_분석(Python)

#2 2일차_랜덤포레스트 (분류), SVM (Support Vector Machine)

ecosso 2026. 6. 2. 17:08

01 랜덤포레스트 (분류)

 -01 트리의 성장

 -02 랜덤포레스트의 장단점

 -03 분석코드

 

02 SVM (Support Vector Machine)


01 랜덤포레스트 (분류)

 - 앙상블 모형 : 동일하거나 다른 모델을 결합하여 하나의 의사결정을 하도록 만드는 과정이다.

 - 여러 개의 의사결정나무를 결합한 앙상블 모형이다.

 - 목적은 서로 다른 트리를 구성함으로써 :

  1) 부트스트랩 :  복원추출을 허용하여 크기는 같지만 구성이 다른 샘플을 만드는 과정

  2) 임의성정도 (max_features) : 가지 성장 시 (split) 일부 독립변수만 고려하여 자식노드로 분할

  3) 배깅 (bootstrap + aggregating) : 각 트리의 학습 결과를 최종 결합 (다수결, 평균)하여 하나의 결과를 만드는 과정

 

 -01 트리의 성장

  1) 불순도 감소량이 가장 큰 변수를 사용하여 분할을 진행함 (분류트리)

  > 불순도 : gini index, entropy...

  > 불순도 감소량 : 정보이득 (IG : Information Gain), 카이제곱통계량 (적합도 검정 : 멘델의 유전법칙을 기억하기)

 

  2) 분산 감소량이 가장 큰 변수를 사용하여 분할을 진행함 (회귀트리)


 -02 랜덤포레스트의 장단점

  1) 장점

  - 스케일에 민감하지 않다.

  - 이상치에 민감하지 않다.

  - 변수 중요도를 계산 · 제공하므로 변수 선택에 대한 부담이 적다.

 

  2) 단점

  - 트리가 많을수록 학습 속도과 느려진다. 

  (병렬처리 → CPU core 수가 많을수록 병렬처리의 효과가 극대화된다.)


 -03 분석코드
import sklearn.ensemble
dir(sklearn.ensemble)
* RF 기반의 이상치 검정 시 : IsolationForest

import sklearn.ensemble import RandomForestClassifier
RandomForestClassifier(n_estimators = 100,
                                        ..., 
                                       max_features = 'sqrt',
                                       n_jobs,                         # 병렬처리할 CPU processor 수              

                                       class_weight =,            # balanced (클래스 불균등 시 가중치 조절 방식)
                                       )                                    # {0:1, 1:5} 직접 클래스별 가중치 전달 가능

# n_jobs = -1로 설정(모든 프로세스를 다 사용) 시 다른 업무가 비정상종료 될 수 있다.


[ 예제 - iris data 종 분류 (RF) ]
# step1) 데이터 불러오기
import pandas as pd
iris = pd.read_csv('iris.csv', header = None)

iris 
Out[7]: 
       0    1    2    3               4
0    5.1  3.5  1.4  0.2     Iris-setosa
1    4.9  3.0  1.4  0.2     Iris-setosa
2    4.7  3.2  1.3  0.2     Iris-setosa
3    4.6  3.1  1.5  0.2     Iris-setosa
4    5.0  3.6  1.4  0.2     Iris-setosa
..   ...  ...  ...  ...             ...
145  6.7  3.0  5.2  2.3  Iris-virginica
146  6.3  2.5  5.0  1.9  Iris-virginica
147  6.5  3.0  5.2  2.0  Iris-virginica
148  6.2  3.4  5.4  2.3  Iris-virginica
149  5.9  3.0  5.1  1.8  Iris-virginica

[150 rows x 5 columns]

 

iris.columns = ['sepal.length','sepal.width','petal.length','petal.width','species']
iris['species'] = iris['species'].str.replace('Iris-','')

y = iris['species']
X = iris.drop(columns = 'species')

* y의 경우 라벨 인코딩, 딥러닝 사용 시 원핫인코딩


# step2) 데이터 분리
from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(X, y, random_state = 0)



# step3) 모델링
from sklearn.ensemble import RandomForestClassifier
m_rf = RandomForestClassifier()
m_rf.fit(train_x, train_y)


# step4) 평가
m_rf.score(train_x, train_y)

m_rf.score(train_x, train_y)
Out[19]: 1.0


m_rf.score(test_x, test_y)

m_rf.score(test_x, test_y)
Out[20]: 0.9736842105263158

# step5) 매개변수 튜닝

1) max_features

설명변수의 후보이기 때문에 최솟값은 1, 최댓값은 설명변수의 갯수만큼 설정이 가능하다.
score_tr = []; score_te = []
for i in range(1,5) :
    m_rf = RandomForestClassifier(random_state = 0, max_features = i)
    m_rf.fit(train_x, train_y)
    score_tr.append(m_rf.score(train_x, train_y))
    score_te.append(m_rf.score(test_x, test_y))
    
import matplotlib.pyplot as plt
plt.plot(range(1,5), score_tr, label = 'train_score')
plt.plot(range(1,5), score_te, label = 'train_score')
plt.xthicks(range(1,5))
plt.legend()

max_features는 RandomForest의 하이퍼파라미터로, Iris 데이터의 설명변수 개수(feature 수)가 4개뿐이라서 max_features를 1~4로 바꿔도 큰 차이가 나지 않는다.


# 2) min_sample_split
score_tr = []; score_te = []
for i in range(2,11) :
    m_rf = RandomForestClassifier(random_state = 0, min_samples_split = i)
    m_rf.fit(train_x, train_y)
    score_tr.append(m_rf.score(train_x, train_y))
    score_te.append(m_rf.score(test_x, test_y))
    
import matplotlib.pyplot as plt
plt.plot(range(2,11), score_tr, label = 'train_score')
plt.plot(range(2,11), score_te, label = 'train_score')
plt.xthicks(range(2,11))
plt.ylim([0.96, 1.01])
plt.legend()

5 정도가 적합하며 6부터는 과소적합 (트리의 depth가 지나치게 짧음) 으로 판단된다.


# step6) 최종모형 선택

 - 매개변수 튜닝값으로 학습

 - 전체 학습

 

m_rf = RandomForestClassifier(random_state = 0, max_features= 5)
m_rf.fit(X,y)

 


# step7) 예측
m_rf.predict(X)

m_rf.predict(X)
Out[39]: 
array(['setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
       'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',
       'setosa', 'setosa', 'setosa', 'setosa', 'setosa', 'setosa',

 

m_rf.predict_proba(X)

m_rf.predict_proba(X)
Out[40]: 
array([[1.  , 0.  , 0.  ],
       [1.  , 0.  , 0.  ],
       [1.  , 0.  , 0.  ],
       [1.  , 0.  , 0.  ],

 

[ 예제 - cancer 데이터에 대한 종양의 양성 / 악성 여부 예측 (RF) ]

# step1) 데이터 로딩
df = pd.read_csv('cancer.csv')
df.drop(columns = 'id', inplace = True)
y = df['diagnosis']
X = df.drop(columns = 'diagnosis')


# step2) 데이터 분리
from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(X,y,random_state = 0)


# step3) 모델링
from sklearn.ensemble import RandomForestClassifier
m_rf = RandomForestClassifier()
m_rf.fit(train_x, train_y)

# ** 결과 확인
cancer_imp = pd.Series(m_rf.feature_importances_, index = X.columns)
cancer_imp.sort_values(ascending = False)

cancer_imp.sort_values(ascending = False)
Out[72]: 
perimeter_worst            0.162153
concave_points_worst       0.134474
radius_worst               0.130529
area_worst                 0.097703
concave_points_mean        0.093264
concavity_mean             0.055360
area_mean                  0.050653
perimeter_mean             0.048600
area_se                    0.031843
concavity_worst            0.026910
radius_mean                0.025477
texture_worst              0.021847
compactness_worst          0.016408
perimeter_se               0.012968
smoothness_worst           0.012051
texture_mean               0.010744
radius_se                  0.008812
smoothness_mean            0.007572
symmetry_worst             0.006919
compactness_se             0.005863
compactness_mean           0.005707
symmetry_mean              0.005283
texture_se                 0.004420
fractal_dimension_se       0.004148
smoothness_se              0.003874
fractal_dimension_worst    0.003801
fractal_dimension_mean     0.003579
symmetry_se                0.003112
concave_points_se          0.002971
concavity_se               0.002956
dtype: float64

 

변수 중요도의 경우 Decision Tree와 Random Forest 간에 일부 차이가 나타날 수밖에 없다.

그러나 변수 선택 결과는 래퍼(Wrapper), 필터(Filter), 임베디드(Embedded) 기법 등 적용하는 방법에 따라 달라질 수 있으므로, 하나의 결과를 맹신하는 것보다 다양한 기법을 비교·검토하는 과정이 필요하다.

또한 최종 변수 선정에는 분석가의 도메인 지식과 판단이 함께 반영되어야 한다.


# step5) 매개변수 튜닝
1) max_features
    
len(X.columns) # 30

score_tr = []; score_te = []
for i in range(1,31) :
    m_rf = RandomForestClassifier(random_state = 0, max_features = i)
    m_rf.fit(train_x, train_y)
    score_tr.append(m_rf.score(train_x, train_y))
    score_te.append(m_rf.score(test_x, test_y))
    
import matplotlib.pyplot as plt
plt.plot(range(1,31), score_tr, label = 'train_score')
plt.plot(range(1,31), score_te, label = 'train_score')
plt.xthicks(range(1,31))
plt.legend()


 

# 2) min_sample_split
score_tr = []; score_te = []
for i in range(2,21) :
    m_rf = RandomForestClassifier(random_state = 0, min_samples_split = i)
    m_rf.fit(train_x, train_y)
    score_tr.append(m_rf.score(train_x, train_y))
    score_te.append(m_rf.score(test_x, test_y))
    
import matplotlib.pyplot as plt
plt.plot(range(2,21), score_tr, label = 'train_score')
plt.plot(range(2,21), score_te, label = 'train_score')
plt.xthicks(range(2,21))
plt.ylim([0.96, 1.01])
plt.legend()


# step6) 최종모형 선택
m_rf = RandomForestClassifier(random_state = 0, min_samples_split= 6, max_features = 4)
m_rf.fit(X,y)


# step7) 예측
m_rf.predict_proba(X)       # Benign, Malignant 순서대로 도출

m_rf.predict_proba(X)
Out[90]: 
array([[0.0563254 , 0.9436746 ],
       [0.03281385, 0.96718615],
       [0.        , 1.        ],
       ...,
       [0.03408333, 0.96591667],
       [0.        , 1.        ],
       [0.988     , 0.012     ]], shape=(569, 2))


y.unique()

y.unique()
Out[91]: array(['Malignant', 'Benign'], dtype=object)

 

result = m_rf.predict_proba(X)[:,1]

result
Out[98]: 
array([0.9436746 , 0.96718615, 1.        , 0.89759127, 0.93895238,
       0.88954365, 1.        , 0.9725    , 0.96122222, 0.95407143,
       0.79592063, 1.        , 0.9979798 , 0.85550794, 0.95963095,
       0.995     , 0.95783333, 1.        , 1.        , 0.00366667,
       0.023     , 0.        , 0.96966667, 0.99509091, 1.        ,

# step8) 결과 제출
df = pd.DataFrame({'pred':result})
df.to_csv('result.csv', index = False)


02 SVM (Support Vector Machine)

 - 분류 / 회귀 가능

 - 예측력이 강하고 쉽게 과적합 되지 않는 모델 (파라미터 조절 필요)

 - 계산량이 많고 모델 내부가 복잡함 → 해석의 어려움 (예측 초점)

 - 고차원 데이터, 많은 양의 데이터 학습에 유리x

 

 * 용어 정리

 1) 결정경계 : 클래스를 분류하는 경계

 2) 초평면  : 다차원 공간에서의 분류경계

 3) 커널트릭 : 실제 고차원 데이터로 변경하지는 않지만 마치 고차원 데이터로 변경하는 연산식(함수)을 통해 고차원 매핑을 유도하는 과정 (함수)

  - kernel = 'rbf'                   default, 가장 많이 사용함, 비선형결정경계를 유도하는 차원 확장

  - kernel = 'poly'                다항식 추가(x1**2, x1**3)

  - kernel = 'sigmoid'

  - kernel = 'linear' 

 

 4) 슬랙변수 : 결정경계를 만드는 과정에서 허용하는 오차, 슬랙변수의 강도를 C 매개변수로 결정

  C 작으면 : 오차허용 O -> 모델 복잡도가 낮아짐 (선형 경계)

  C 크면    : 오차허용 X -> 모델 복잡도가 증가함 (비선형 경계)

 

5) gamma : 결정경계를 구성하는 데이터포인트의 허용 범위를 결정하는 매개변수

  gamma가 작을수록 -> 전체 데이터를 고려하여 결정경계 생성 -> 서포트벡터의 가중치가 상대적으로 작게 설정됨 -> 단순 경계

  gamma가 커질수록 -> 결정경계 인근 데이터만 고려하여 결정경계 생성 -> 서포트벡터의 가중치가 상대적으로 높게 설정됨 -> 복잡한 경계

 

  예) x1, x2로 2차원 공간선상에서 분류 경계 복잡

  x2**2 추가 -> 3차원 공간선상에서 분류 경계 단순

  f(x) -> 고차원 데이터


[ 예제 - SVM 모델의 결정경계 시각화 ]
# step1) 데이터 로딩
from sklearn.datasets import make_blobs
X, y = make_blobs(centers = 4, random_state = 8)
y = y % 2       # 이진클래스 분류과제를 위해 2로 나눈 나머지값으로 변경



# step2) 분포 시각화
# pip install mglearn

import mglearn

mglearn.discrete_scatter(X[:,0],        # x축 좌표 (첫 번째 설명변수)
                         X[:,1],        # y축 좌표 (두 번째 설명변수)
                         y=y,           # class 정보 (target 변수)
                         s=8)           # 점 크기

선형결정경계가 불가능한 상황이다.


# step3) 선형 분류기를 사용한 선형 결정 경계 생성
from sklearn.svm import LinearSVC, SVC
import sklearn.svm
dir(sklearn.svm)

m_svc1 = LinearSVC()
m_svc1.fit(X,y)     # 결정경계를 생성하는 과정

** 결과 확인
m_svc1.coef_        # x1, x2에 대한 기울기
m_svc1.intercept_   # 절편

** 결정경계 시각화
mglearn.plots.plot_2d_separator(classifier,     # 분류모델
                                X)              # 설명변수 집합

mglearn.plots.plot_2d_separator(m_svc1, X)


# step4) 비선형 분류기를 사용한 선형 결정 경계 생성
m_svc2 = SVC()
m_svc2.fit(X,y)

mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc2, X)

 

** C의 변화에 따른 결정경계 시각화

** C는 오차 허용 수준의 개념
m_svc3 = SVC(C = 0.001)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)


# step5) 차원 증가에 따른 결정경계(초평면) 시각화
import numpy as np
X_new = np.hstack([X, X[:,1:2]**2])


# ** 3차원 공간에 시각화
from mpl_toolkits.mplot3d import axes3d

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')


# y==0일때 산점도)
ax.scatter(X_new[y==0, 0],         # X축 좌표
           X_new[y==0, 1],         # Y축 좌표    
           X_new[y==0, 2],         # Z축 좌표
           c = 'b',                # 점 색
           s=60,                   # 점 크기
           edgecolors = 'k')       # 점 테두리 색

# y==1일때 산점도)
ax.scatter(X_new[y==1, 0],         # X축 좌표
           X_new[y==1, 1],         # Y축 좌표    
           X_new[y==1, 2],         # Z축 좌표
           c = 'r',                # 점 색
           s=60,                   # 점 크기
           edgecolors = 'k')       # 점 테두리 색


# 초평면(분류평면) 유도 및 시각화
m_svc4 = LinearSVC()
m_svc4.fit(X_new, y)

intercept = m_svc4.intercept_      # 초평면 절편
coef = m_svc4.coef_.ravel()        # 초평면 기울기

# 시각화
np.linspace(-3,3,1000)             # -3부터 3까지 1000개로 균등 분할

xx = np.linspace(X_new[:,0].min() - 2, X_new[:,0].max() + 2, 1000)
yy = np.linspace(X_new[:,1].min() - 2, X_new[:,1].max() + 2, 1000)

XX, YY = np.meshgrid(xx, yy)       # 2차원 공간안의 좌표값으로 변환

# ** f(x) = a1X + a2Y + a3Z + b 의 결정경계 수식으로부터 f(x)의 값이 양수일 경우 양의 클래스로,
#           음수을 경우 음의 클래스로 분류하게 된다.
#           따라서, 양과 음을 분류하기 위해 f(x)값이 0일때를 기준으로 Z좌표를 얻게되면

ZZ = (coef[0] * XX + coef[1] * YY + intercept) / -coef[2]
ax.plot_surface(XX, YY, ZZ, alpha = 0.3)

 


[ 예제 - SVM을 사용한 iris 데이터의 분류 경계 시각화 ]
# step1) 데이터 로딩
from sklearn.datasets import load_iris
iris = load_iris()
X = iris['data']
y = iris['target']


# ** 이진 클래스 분류 문제를 위한 데이터 선택
X = X[y != 0,:][:,[2,3]]  # 3,4번째 설명변수만 선택하여 분석 시도
y = y[y != 0]            # 첫번째 클래스를 제외한 나머지 클래스 선택



# step2) 분포 시각화
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)


# step3) 선형 분류기를 사용한 선형 결정 경계 생성
from sklearn.svm import LinearSVC, SVC
import sklearn.svm

m_svc1 = LinearSVC()
m_svc1.fit(X,y)     # 결정경계를 생성하는 과정

** 결과 확인
m_svc1.coef_        # x1, x2에 대한 기울기
m_svc1.intercept_   # 절편

** 결정경계 시각화
mglearn.plots.plot_2d_separator(classifier,     # 분류모델
                                X)              # 설명변수 집합

mglearn.plots.plot_2d_separator(m_svc1, X)


# step4) 비선형 분류기를 사용한 선형 결정 경계 생성
m_svc2 = SVC()
m_svc2.fit(X,y)

mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc2, X)

** C의 변화에 따른 결정경계 시각화
mglearn.plots.plot_2d_separator(m_svc2, X)

m_svc3 = SVC(C = 0.001)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)

m_svc3 = SVC(C = 0.01)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)

m_svc3 = SVC(C = 1)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)

 

 

** gamma의 변화에 따른 결정경계 시각화

m_svc3 = SVC(gamma = 0.1)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)

 

m_svc3 = SVC(gamma = 10)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)

 

m_svc3 = SVC(gamma = 100)
m_svc3.fit(X,y)
mglearn.discrete_scatter(X[:,0], X[:,1], y=y, s=8)
mglearn.plots.plot_2d_separator(m_svc3,X)


# 참고 : 분석기사실기 / 공모전 분석
X : train / test
y : train
- 데이터만 제공됨
- 성별 예측 (분류분석과제)

pd.read_csv('X_train.csv', encoding = 'cp949')      # raw data(x)
pd.read_csv('X_test.csv', encoding = 'cp949')       # raw data(y)
 -> raw data를 사용하여 다시 75 : 25 로 데이터를 분할하여 학습용 데이터를 만들어야 한다.
 -> 평가 결과를 토대로 최종 모형을 만들고 아래 제출용 데이터셋에 대한 예측 결과를 제출해야 한다.
 
pd.read_csv('y_train.csv', encoding = 'cp949')      # 제출용