01 분석 프로세스
-01 분석 기획
-02 데이터 수집
-03 필요 전처리
-04 모델링
-05 평가
-06 결과해석
02 머신러닝 기반 모델링 기법
-01 회귀 기반
-02 거리 기반
-03 tree 기반
-04 확률 기반
-05 신경망 기반
03 의사결정나무
01 분석 프로세스
-01 분석 기획
(1) 주제 선정 (난이도, 시급성)
(2) 비용 산출
- 회귀 분석 중 데이터가 더 필요한 상황인데, 해당 데이터를 수집하는 과정에 있어 비용이 필요한 상황이 발생할 수 있다.
(유료 데이터 등)
(3) 분석 목적 (예측 (target), 아이디어 도출)
-02 데이터 수집
(1) 내부데이터 : ETL, API, DBtoDB (migration)
(2) 외부데이터 : 크롤링, API, 공공데이터 (API, 다운)
-03 필요 전처리
(1) 노이즈 제거
- 데이터에 분석에 도움이 되지 않는 불필요한 정보가 포함되어 있을 수 있다.
(2) 변수 선택
> 히스토그램을 통한 분포 확인, 왜도 확인, 상관관계 확인 (*), 결측치 / 이상치 확인 등
- 보유하고 있는 데이터가 수치형인지, 범주형인지에 따라 사용하려는 방법이 달라진다.
- 예를 들어,
> 수치형 변수 간 관계 → 피어슨 상관계수(Pearson Correlation)
> 범주형 변수 간 관계 → 카이제곱 검정(Chi-Square Test)
> 연속형·범주형 혼합 데이터 → 다른 통계적 접근 필요
따라서 데이터의 특성을 고려하지 않은 채 무조건 특정 기법을 적용하는 방식은 지양해야 한다.
(3) 변수 변환 (변수 가공)
> 로그변환, 스케일링, 비닝 (수치형 -> 범주형), 파생변수 도출 등
- 특성 공학이라고도 불리우며 가장 심도있게 다루어야하는 부분이다.
- 그래프를 그려보았더니 정규분포를 따르지 않은 경우 로그 스케일링을 한다거나, 로그 스케일링 전후의 점수 비교를 하는 등의 확인이 필요하다.
- 또한 데이터가 연속형이지만 정규분포라 하기에는 꼭지점이 이분할 되듯 2개일 때 중간 지점을 기준으로 0, 1로 변환하는 방법도 존재한다. (Binning : 수치형 자료를 범주형 자료로 변환)
-04 모델링
- 알고리즘 선택
> 분석 목적 / 데이터의 성격
- 특히 군집 분석에서는 단순히 군집을 나누는 것보다 각 군집에 어떤 의미를 부여할 수 있는지 해석하는 과정이 중요하다.
- 또한 개별 변수를 그대로 사용하는 것보다,
> 군집 분석 결과를 새로운 파생 변수로 활용
> 여러 전처리 방법을 조합하여 특성을 재구성
더 좋은 성능을 얻을 수도 있다.
- 따라서 탐색 과정에서는 하나의 알고리즘에 고정되기보다 다양한 접근을 시도해보는 것이 중요하다.
- 과적합 해결
> 데이터 분리, 평가점수 선택, 매개변수 튜닝, 그리드 서치
for i in range(1:21) :
date(max_dep = i)
- 대부분 매개변수 튜닝은 예측력 상승을 위해 존재한다고 생각하나, 과적합 방지에 더 무게가 실려있다.
- 예측력 (점수) 상승을 위해서는 매개변수 튜닝보다 전처리에 집중해야 한다.
- 성능 고도화
> 인코딩 기법 선택, 타겟변수 변환, 클래스 불균형
- 평가점수 일반화 (cross validation : k-fold 등)
-05 평가
- 분석 목적에 맞는 평가지표를 선택해야 한다.
(예를 들어, MSE(Mean Squared Error) 는 오차를 제곱하여 계산하기 때문에 큰 오차에 더 큰 패널티를 부여한다. 따라서 일부 데이터에서 오차가 크게 발생하는 경우 평가 결과가 과도하게 커질 수 있으며, 실제 성능을 해석하는 데 어려움이 생길 수 있다.
이러한 경우에는 MAE(Mean Absolute Error) 와 같이 오차의 절댓값을 기반으로 계산하는 지표를 사용하여 보다 직관적으로 성능을 평가할 수 있다.)
→ 즉, 평가지표는 단순히 관례적으로 선택하는 것이 아니라 데이터의 특성과 분석 목적을 고려하여 결정해야 하며, 프로젝트 진행 시 해당 지표를 선택한 이유와 근거를 명확하게 설명할 수 있어야 한다.
-06 결과 해석
02 머신러닝 기반 모델링 기법
-01 회귀 기반
> 회귀분석 (선형회귀, 릿지, 라쏘 등), 로지스틱 회귀, SVM
- 변수 스케일에 민감
- 이상치에 민감
- 변수 선택 중요성
> 릿지, 라쏘, 엘라스틱넷의 경우 중요하지 않은 변수에 패널티를 주기 때문에 (패널티 모델) 변수 선택에 대한 영향을 적게 받는다.
> 그러나 일반적인 선형회귀, 로지스틱 회귀 등에 대해서는 변수 선택이 매우 중요하다.
- 독립변수 형태에 민감 (수치형 변수들끼리 있으면 가장 좋으나 범주형 변수인 경우 원핫인코딩 수행 필요 -> 차원의 저주 고려)
-02 거리 기반
- knn, 대부분의 군집분석 (hclust, kmeans 등)
- 변수 스케일에 민감
- 이상치에 민감
- 독립변수 형태 민감 (수치형 변수들의 거리 계산이 가장 정확)
-03 tree 기반
- 수치형, 범주형 독립변수 모두 가능
- 내부 변수 중요도 기반으로 변수 선택 가능
- 이상치에 덜 민감
- 변수 스케일에 영향을 받지 않음
- 범주형 자료의 인코딩 시 원핫인코딩이 불필요
-04 확률 기반
- naive bays, 연관성 분석
- 계산속도가 빠르다 -> 고차원 데이터에 유리 (텍스트 데이터 분석에 유리_스팸분류 등)
- 적은 데이터로도 동작
- 결측치에 덜 민감
- 독립변수의 독립성 가정 필요
(정형데이터에서의 분류 과제에서는 적합하지 않을 수 있다.)
-05 신경망 기반
- 변수 스케일링에 매우 민감 (사전에 스케일링이 필수적)
- 변수 선택 가능
(경험적으로 오차를 줄이는 방향으로 변수 가중치를 조절한다. 경험적인 결과를 토대로 변수의 중요도가 결정되기 때문에 변수 선택이 가능하다.)
- 블랙박스 모델이기 때문에 내부 모델 확인 및 해석이 불가 : 예측에만 초점을 맞추는 모델
* 블랙박스(Black Box) 모델
모델이 어떤 과정을 거쳐 결과를 도출했는지 사람이 이해하기 어려운 모델을 의미하며, 대표적인 예제로 신경망(Neural Network)가 존재한다. 입력 변수들이 여러 층(layer)의 수많은 가중치와 활성화 함수를 거치면서 복잡하게 계산되기 때문에, 최종 예측값이 왜 나왔는지 직관적으로 설명하기 어렵다.
03 의사결정나무
- 트리기반 모델의 가장 기본적인 구조이다.
- 단일 의사결정 나무
- 범주형 변수의 인코딩 시 원핫인코딩이 불필요하다. (라벨 인코딩)
** 매개변수
** 모델링
import sklearn.tree
dir(sklearn.tree)
from sklearn.tree import DecisionTreeClassifier
DecisionTreeClassifier?
Init signature:
DecisionTreeClassifier(
*,
criterion='gini',
splitter='best',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
class_weight=None,
ccp_alpha=0.0,
monotonic_cst=None,
)
Docstring:
A decision tree classifier.
Read more in the :ref:`User Guide <tree>`.
min_samples_split : 최소분리개수
min_samples_leaf : leaf node에 있었으면 하는 샘플의 개수
max_features : 가장 중요한 분리기준
random_state : seed 고정 (이후 프로젝트 수행 시 타 모델과의 비교를 진행할 때도 seed 고정을 한다.)
min_impuirty_decrease : 최소 불순도 설정 (3으로 설정한다면 3 이상의 불순도를 가질 때에만 가지를 나누는 식)
[ ex) iris data 종 분류 ]
# step1) 데이터 로딩
from sklearn.datasets import load_iris
iris = load_iris()
type(iris)
type(iris)
Out[10]: sklearn.utils._bunch.Bunch
iris.keys()
iris.keys()
Out[11]: dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
* sklearn.datasets 를 통해 불러온 데이터는 모두 딕셔너리 형태로 로드된다.
X = iris['data']
X
Out[15]:
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2],
y = iris['target']
y
Out[16]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
* 이미 라벨 인코딩이 되어 있는 형태로 target_names를 통해 각 값을 확인할 수 있다.
(target_names 순서대로 0,1,2로 변환)
iris['target_names']
iris['target_names']
Out[17]: array(['setosa', 'versicolor', 'virginica'], dtype='<U10')
# step2) 데이터 분리 (train / test)
from sklearn.model_selection import train_test_split
* 앞으로 프로젝트 수행 시 train, test 데이터 분리 시 train_test_split 를 사용한다.
(기본 비율은 75 : 25로 설정되어 있으며 변경을 원할 시 내부에 옵션이 존재한다.)
두 집단을 나누어주는 것이 해당 기능이며 validation 데이터는 다음과 같이 분리된다.
● train_test_split 수행시
train (75%) : test (25%)
| train data (75%) | test data (25%) |
이후 train으로 나누어진 덩어리를 한 번 더 나누었을 시 더 큰 쪽이 train (75%), 작은 쪽이 validation (25%) 이다.
| train data (75%) | validation data (25%) |
=> 즉, validation data를 나누어주는 기능은 없다! (처음부터 train, validation, test 세 덩어리로 나누지 않는다.)
train_test_split를 두 번 수행하면 된다.
train_test_split?
Signature:
train_test_split(
*arrays, # 분리할 데이터셋
test_size=0.25, # test 데이터 비율
train_size=0.75, # train 데이터 비율 (test_size와 train_size 둘 중 하나만 전달)
random_state=None, # seed 고정값
shuffle=True, # 셔플 여부
stratify=None, # 클래스 비율 유지 여부
)
Docstring:
Split arrays or matrices into random train and test subsets.
stratify : 옵션은 훈련 데이터(train)와 테스트 데이터(test)를 나눌 때 원본 데이터의 클래스 비율을 유지하도록 하는 옵션으로,
클래스 불균등이 심한 경우 (8:2를 벗어나는 순간 심각하다고 판단한다.) 해당 옵션을 켜주는 것이 좋다.
>>> X_train, X_test, y_train, y_test = train_test_split(
... X, y, test_size=0.33, random_state=42)
train_test_split(X,y,z)
세 개의 그룹으로도 나눌 수 있다.
train_x, test_x, train_y, test_y = train_test_split(X, y, random_state=0)
train_x.shape
train_y.shape
# step3) 모델링
from sklearn.tree import DecisionTreeClassifier
# 모델 정의
m1 = DecisionTreeClassifier()
# 모델 학습
m1.fit(train_x, train_y)
# 모델이 호출 가능한 메서드 목록 확인
dir(m1)
'score',
* model fitting 만 진행되면 하위요소를 모두 전달해준다.
# ** 모델 결과 확인
import pandas as pd
m1.feature_importances_ # 변수 중요도 확인
m1.feature_importances_ # 변수 중요도 확인
Out[40]: array([0. , 0.02014872, 0.39927524, 0.58057605])
s_imp = pd.Series(m1.feature_importances_, index = iris['feature_names'])
s_imp.sort_values(ascending = False)
s_imp.sort_values(ascending = False)
Out[51]:
petal width (cm) 0.580576
petal length (cm) 0.399275
sepal width (cm) 0.020149
sepal length (cm) 0.000000
dtype: float64
# step4) 평가
m1.score(train_x, train_y)
m1.score(train_x, train_y)
Out[38]: 1.0
m1.score(test_x, test_y)
m1.score(test_x, test_y)
Out[39]: 0.9736842105263158
분류모델의 경우 acuuracy, 회귀모델의 경우 R²를 제시하도록 설정되어 있다.
( R² 의 경우 수정 R² 이 아니다.)
# step5) 매개변수 튜닝
Init signature:
DecisionTreeClassifier(
*,
criterion='gini',
splitter='best',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
class_weight=None,
ccp_alpha=0.0,
monotonic_cst=None,
)
Docstring:
A decision tree classifier.
Read more in the :ref:`User Guide <tree>`.
# ** 매개변수
1) max_depth : 트리의 총 길이
2) min_samples_split = 2 : 최소 노드 분할수
- 각 노드의 최소 분할 오분류 수 (이 값보다 오분류 데이터가 많으면 추가 분리를 진행)
- min_samples_split 값이 작을수록 복잡한 트리를 구성
3) max_features
- 설명변수 후보 수 (임의성 정도)
- 설명변수에서 일부만 랜덤하게 추출하여 이 중 중요도가 높은 변수로 트리 분할 진행
- 랜덤포레스트 시 사용되는 매개변수로 값ㅅ이 클수록 서로 비슷한 트리를 구성
4) class_weight : 클래스 가중치 조절 (★)
ex) 생존 vs 사망 중 소수클래스(사망)에 대한 예측이 매우 중요한 경우, 모델 학습 과정에서 소수클래스의 예측이 실패했을 때의 패널티를 더 강하게 부여함으로써 다수클래스보다 소수클래스 예측을 강화한다.
● 클래스 불균등 발생 시
1) 샘플링 : 언더샘플링, 오버샘플링
2) 클래스 가중치 조절
3) 임계값 조절 : 성공과 실패를 나누는 지점 (보통 0.5로 설정되어 있음)을 조정한다.
score_tr = [] ; score_te = []
for i in range(2,11) :
model1 =DecisionTreeClassifier(min_samples_split = i)
model1.fit(train_x, train_y)
score_tr.append(model1.score(train_x, train_y))
score_te.append(model1.score(test_x, test_y))
df_score = pd.DataFrame({'min_samples_split':range(2,11),
'score_tr':score_tr,
'score_te':score_te})
# 시각화
import matplotlib.pyplot as plt
plt.plot(range(2,11), score_tr, label = 'train_score')
plt.plot(range(2,11), score_te, label = 'test_score')
plt.legend()
plt.ylim([0.90, 1.1])

# step6) 예측결과 확인
1) 예측 클래스 확인
m1.predict(test_x) # 기본 임계값을 기준으로 target 값 변환한 값
** 다중 클래스의 경우 각 클래스별 확률이 가장 큰 지점의 클래스값이 최종 예측값이 된다. (softmax)
predict 결과와 같다.
2) 각 클래스별 확률
prob1 = m1.predict_proba(test_x) # 기본 임계값을 기준으로 target 값 변환한 값
prob1[:,0] # setosa일 확률 (Y=0)
prob1[:,1] # setwersicolor일 확률 (Y=1)
prob1[:,2] # virginica일 확률 (Y=2)
prob1[:,0]
Out[57]:
array([0., 0., 1., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.,
0., 1., 1., 0., 0., 1., 1., 0., 1., 1., 0., 0., 1., 0., 0., 1., 0.,
0., 0., 1., 0.])
prob1[:,1]
Out[58]:
array([0., 1., 0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 1., 1., 1., 0., 1.,
1., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0., 0.,
0., 1., 0., 0.])
prob1[:,2]
Out[59]:
array([1., 0., 0., 1., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 1.,
1., 0., 0., 1.])
prob1.argmax(axis=1)
prob1.argmax(axis=1)
Out[77]:
array([2, 1, 0, 2, 0, 2, 0, 1, 1, 1, 2, 1, 1, 1, 1, 0, 1, 1, 0, 0, 2, 1,
0, 0, 2, 0, 0, 1, 1, 0, 2, 1, 0, 2, 2, 1, 0, 2])
확률값을 바탕으로 예측값을 말해준다.
[ 연습문제 - cancer 데이터의 종양의 양성 / 악성 분류 ]
최종모델이 아님에도 불구하고 decision tree를 사용하는 이유는 시각화가 가능하기 때문이다.
# STEP1) 데이터로딩
df = pd.read_csv('cancer.csv')
df.drop(columns = 'id', inplace = True)
y = df['diagnosis']
y
Out[188]:
0 Malignant
1 Malignant
2 Malignant
3 Malignant
4 Malignant
564 Malignant
565 Malignant
566 Malignant
567 Malignant
568 Benign
Name: diagnosis, Length: 569, dtype: object
X = df.drop(columns='diagnosis')
X
Out[189]:
radius_mean texture_mean ... symmetry_worst fractal_dimension_worst
0 17.99 10.38 ... 0.4601 0.11890
1 20.57 17.77 ... 0.2750 0.08902
2 19.69 21.25 ... 0.3613 0.08758
3 11.42 20.38 ... 0.6638 0.17300
4 20.29 14.34 ... 0.2364 0.07678
.. ... ... ... ... ...
564 21.56 22.39 ... 0.2060 0.07115
565 20.13 28.25 ... 0.2572 0.06637
566 16.60 28.08 ... 0.2218 0.07820
567 20.60 29.33 ... 0.4087 0.12400
568 7.76 24.54 ... 0.2871 0.07039
[569 rows x 30 columns]
# STEP2) 데이터 분리(train/test)
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.tree import DecisionTreeClassifier
m1 = DecisionTreeClassifier(random_state=0) # 모델 정의
m1.fit(train_x, train_y) # 학습
# STEP4) 평가
m1.score(train_x, train_y) # 1.0
m1.score(test_x, test_y) # 0.8811
m1.score(train_x, train_y) # 1.0
Out[195]: 1.0
m1.score(test_x, test_y) # 0.8811
Out[196]: 0.8811188811188811
# STEP5) 매개변수 튜닝
score_tr = [] ; score_te = []
for i in range(2,21) :
model1 = DecisionTreeClassifier(min_samples_split=i, random_state=0)
model1.fit(train_x, train_y)
score_tr.append(model1.score(train_x, train_y))
score_te.append(model1.score(test_x, test_y))
df_score = pd.DataFrame({'min_samples_split':range(2,21),
'score_tr':score_tr,
'score_te':score_te})
import matplotlib.pyplot as plt
plt.plot(range(2,21), score_tr, label = 'train_score')
plt.plot(range(2,21), score_te, label = 'test_score')
plt.xticks(range(2,21))
plt.legend()
plt.ylim([0.80,1.05])

# STEP6) 최종모델 확인
m1 = DecisionTreeClassifier(min_samples_split=6, random_state=0)
m1.fit(train_x, train_y)
# STEP7) 예측결과 확인
# 1) 각 클래스별 확률
prob1 = m1.predict_proba(test_x)
prob1
Out[204]:
array([[0. , 1. ],
[1. , 0. ],
[1. , 0. ],
[1. , 0. ],
[1. , 0. ],
[1. , 0. ],
[1. , 0. ],
# 2) 예측 클래스 확인
m1.predict(test_x)
m1.predict(test_x)
Out[205]:
array(['Malignant', 'Benign', 'Benign', 'Benign', 'Benign', 'Benign',
'Benign', 'Benign', 'Benign', 'Benign', 'Malignant', 'Benign',
'Benign', 'Malignant', 'Malignant', 'Malignant', 'Benign',
# ** Decision Tree 시각화
1) graphviz 설치(window용)
download => https://graphviz.gitlab.io/_pages/Download/Download_windows.html
=> window용 64bit 설치파일 다운 => 실행
=> path 등록(설치과정에서 선택) => 설치위치 확인(C:\Program Files)
2) graphviz 설치(python용)
pip install graphviz(cmd에서 수행)
import graphviz
3) python path 등록
import os
os.environ['PATH'] += os.pathsep + 'C:/Program Files/Graphviz/bin' # (디렉토리 구분기호는 \\ or /로 전달)
os.environ['PATH'] # 맨 뒤에 추가된 패스 확인
4) graphviz를 사용한 시각화
import graphviz
from sklearn.tree import export_graphviz
cname = pd.Series(y.unique()).sort_values().values
export_graphviz(m1, # 시각화 할 모델명
out_file='tree.dot', # 저장할 파일명
class_names=cname, # Y 이름(학습되는 Y의 형태가 숫자로 변환된 경우 필수 전달)
feature_names=X.columns, # 설명변수 이름
impurity = False, # 불순도 출력 여부
filled = True) # 노드 이름 출력 여부
# 파일 인코딩 변환
with open('tree.dot', encoding='UTF8') as f :
dot_graph = f.read()
# 원하는 형태로 파일 변경
g1 = graphviz.Source(dot_graph)
g1.render('decision_cancer', cleanup=True)

'아이티윌_데이터 분석 55기 > 강의내용 필기_분석(Python)' 카테고리의 다른 글
| #6 교호작용 및 효과 검증 (0) | 2026.06.09 |
|---|---|
| #5 5일차_데이터 분석 과정, 로지스틱 회귀, 교호작용 (0) | 2026.06.08 |
| #4 4일차_복사 / SVM·RF 실습 / 모델링 파이프 라인 구축 / 분류 모델 / knn (0) | 2026.06.05 |
| #3 3일차_SVL 실습, 독립변수 스케일링 + 연습문제 및 문제풀이 (0) | 2026.06.04 |
| #2 2일차_랜덤포레스트 (분류), SVM (Support Vector Machine) (0) | 2026.06.02 |