ㅅㅇ
머신러닝 _ 02 머신러닝분석 - lris 분석 본문
머신러닝 _ 02 머신러닝분석 - lris 분석
1. Iris DataSet
꽃받침(Sepal)과 꽃잎(Petal)의 길이, 너비 네가지 feature로
Setosa, Versicolor, Virginica 아이리스 세가지 품종 Label 을 분류
- 식물에 대한 전문가가 아닌 프로그래머가 꽃에 대한 규칙을 알기 어렵다.
사람이 직접 찾는 규칙기반에서는 iris 전문가가 필요하다.
- 머신러닝은 데이터만으로 컴퓨터가 직접 패턴을 찾는 것이다.
- 사실, 머신러닝에서 중요도를 따지면 알고리즘은 20~30%이다.
성능의 차이는 데이터에서 난다. 머신러닝에서는 데이터 전처리가 중요하다.
패턴을 알 수 있는 유의미한 데이터를 구하는 것이 중요. (딥러닝에서는 또 다름.)
2. 데이터 셋 확인하기
2.1 scikit-learn 내장 데이터셋 가져오기
- scikit-learn은 머신러닝 모델을 테스트 하기위한 데이터셋을 제공한다.
- 이런 데이터셋을 Toy dataset이라고 한다. 실무에서 이것을 사용하진 않는다.
- 패키지 : sklearn.datasets
- 함수 : load_xxxx()
- xxxx : 어떤 데이터 셋인지
- bunch 반환
from sklearn.datasets import load_iris
iris = load_iris() # iris 라는 데이터 셋을 load
2.2 scikit-learn 내장 데이터셋의 구성
- 'scikit-learn의 dataset' 은 딕셔너리 구조의 Bunch 클래스 객체이다.
- keys() 함수로 key값들을 조회.
# bunch type : dictionary 구현체 (dict처럼 여러 개 값이 있고 key값이 있음.)
type(iris)
sklearn.utils.Bunch
- 구성
iris.keys()
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
위와 같은 key 를 가지고 있다.
- target_names : 예측하려는 값(class)을 가진 문자열 배열. label숫자의 의미를 가지고 있다.
- target : Label(출력데이터) 숫자로 구성되어 있다.
- data : Feature(입력변수)
- feature_names : 입력변수 각 항목의 이름
- DESCR : 데이터셋에 대한 설명
- filename : 파일 이름 (이전 버전에서는 경로까지 였으나 현재는 'iris.csv' 파일 이름만이 뜬다.
1) DESCR 조회 : 데이터셋에 대한 설명
iris.DESCR
2) Target 조회
- target 조회
target 의 타입은 numpy.ndarray 로 (150, ) 1차원 배열 구조에 Label(출력데이터) 숫자가 담겨 있다.
# 방법1
iris.target
# 방법2
iris['target']
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,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
- target_names 조회
ndarray의 index : label(숫자label), ndarray의 value : label name
0 : 'setosa', 1: 'versicolor', 2 : 'virginica'
iris.target_names
array(['setosa', 'versicolor', 'virginica'], dtype='<U10')
- target 출력 데이터 (정답개수, ) = > (150, ) # 정답개수니 당연히 하나의 축으로 끝남.
iris.target.shape
(150,)
3) Feature 조회
- Feature 조회
target 의 타입은 numpy.ndarray 로 (150, 4) 2차원 배열 구조에 Feature(입력변수) 데이터가 담겨 있다.
iris.data
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],
[5.4, 3.9, 1.7, 0.4],
[4.6, 3.4, 1.4, 0.3],
[5. , 3.4, 1.5, 0.2],
[4.4, 2.9, 1.4, 0.2],
.
.
.
- Feature 데이터 (150, 4) = > (0번 축 : 데이터 개수, 1번 축 : Feature의 개수)
iris.data.shape
(150, 4)
- feature_names 조회
입력변수 각 항목의 이름이 리스트로 담겨져 있다.
# 네가지 feature 의 name
iris.feature_names
['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
2.2 데이터 셋을 판다스 데이터프레임으로 구성
1) 데이터 프레임 생성
import numpy as np
import pandas as pd
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_df['species'] = iris.target
iris_df.head()
2) 데이터프레임 info() 확인
iris_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal length (cm) 150 non-null float64
1 sepal width (cm) 150 non-null float64
2 petal length (cm) 150 non-null float64
3 petal width (cm) 150 non-null float64
4 species 150 non-null int32
5 species_name 150 non-null object
dtypes: float64(4), int32(1), object(1)
memory usage: 6.6+ KB
3) 각 species(target) 별 describe() 통계값 확인
iris_df.groupby('species').describe().T
4) 전체 데이터에 대한 descirbe() 통계량 확인
iris_df.describe()
5) 만약, label (숫자)에 따른 target name 을 보고 싶다면?
iris_df['species_name'] = iris_df['species'].apply(lambda x:iris.target_names[x])
iris_df.head()
3. 머신러닝을 이용한 예측
문제 정의
내가 발견한 Iris 꽃받침(Sepal)의 길이(length)와 폭(width)이 각각 5cm, 3.5cm이고
꽃의 꽃잎(Petal)의 길이와 폭은 각각 1.4cm, 0.25cm이 이었다.
이 꽃는 Iris의 무슨 종일까?
- 규칙기반으로 찾아본다면?
꽃받침(Sepal)의 길이(length): 5cm, 폭(width): 3.5cm
꽃잎(Petal) 의 길이(length): 1.4cm, 폭(width): 0.25cm
내가 가지고 있는 150 개의 데이터를 가지고 우리가 직접 규칙 패턴을 찾는다.
조회 결과 setosa 뿐이다. 이를 통해 setosa 라 예측할 수 있다.
iris_df.loc[(iris_df['sepal length (cm)']==5) & (iris_df['sepal width (cm)']==3.5)]
그러나, 우리가 가지고 있는 데이터는 150개 뿐이다. 전세계 모든 데이터를 가지고 있지 않으며, 심지어 시간에 따라 데이터는 변할 텐데, 규칙기반의 경우 데이터가 바뀔 때 마다 조건을 바꿔주며 규칙을 찾을 것이다.
- 머신러닝으로 우리가 하려는 것은?
프로그래머가 직접 규칙(패턴)을 만드는 대신
컴퓨터가 데이터를 학습하여 규칙을 자동으로 만들도록 하는 것
4. 결정 트리(Decision Tree) 알고리즘을 이용한 분류
결정 트리 알고리즘 개요
: 독립 변수의 조건에 따라 종속 변수를 분리
- 머신러닝의 몇 안되는 White box 모델
- 결과에 대한 해석이 가능하다.
white box model : 모델이 물리 법칙으로 표현이 가능한 수준이며, 변수도 모두 아는 모델.
gray box model : 어느 정도 물리 법칙으로 표현이 가능하며, 변수도 어느 정도 알고 있는 모델.
black box model : 모델이 물리 법칙으로 표현하기 어려울 정도로 복잡하고, 변수도 알기 힘든 모델.
- 과적합(Overfitting)이 잘 일어나는 단점이 있다.
- 랜덤 포레스트(Random Forest), Gradient Boosting, Adaptive boosting과 같은 Boosting 계열 앙상블이 결정트리를 기반으로 하고 있다
- 분류와 회귀 모두 가능하다. 범주나 연속형 수치 모두 예측할 수 있다.
- Decision Tree 의 개념
해당 질문(조건)에 한 범주로 유일하게 만족하는 결과가 나오도록 계속해서 데이터를 분리하며 찾는다.
계속적인 질문으로 그룹 짓어 분리하며 하나의 그룹에 하나의 종류만 나오게 한다.
질문을 던져 대상을 좁혀나가는 스무고개 와 비슷한 개념이다.
- 가장 완벽하게 나눌 수 있는, 가장 분류가 잘 되는 질문을 가장 먼저 한다. - 불순도(불확실성)을 낮게 만드는 질문
- root node : 아무런 분기가 일어나지 않은 상태
'sepal length (cm)'] > 5 입니까? 그 질문에 따라 Yes or No로 데이터를 분리하였다. 이와 같이 분리해가는 것과 같다.
# target 별 5 이상인 데이터 개수
iris_df.loc[iris_df['sepal length (cm)'] > 5, 'species_name'].value_counts()
virginica 49
versicolor 47
setosa 22
Name: species_name, dtype: int64
4.2 결정트리 모델을 이용해 머신러닝 구현
실제로 이렇게 하지 않음. 평가가 빠졌다. 설명을 위해 따로.
1) import 모델
import numpy as np
from sklearn.tree import DecisionTreeClassifier
2) 모델 생성
- DecisionTreeClassifier 클래스의 객체를 생성
tree_model = DecisionTreeClassifier(max_depth=2, random_state=0)
3) 모델 학습시키기
- 생성된 모델객체는 기본공식만 가지고 있다. 이를 학습을 시킨다.
학습 : '기본공식' 을 '내 데이터셋' 에 맞추는 작업. = = > fit(feature, label)
# tree_model 객체 에 나의 150 개의 데이터가 fit 학습 되었다.
tree_model.fit(iris.data, iris.target)
4) 예측
- 분류예측에서
- 모델.predict(추론할 데이터의 feature) : 확률이 가장 높은 class를 반환
- 모델.predict_proba(추론할 데이터의 feature) : 각 class별 확률.
ex) 내가 본 iris 꽃의 꽃잎/꽃받침의 길이, 너비를 재서 종류를 예측해보자.
# 두 꽃 데이터에 대한 [[데이터1], [데이터2]] # 데이터 여러 개면 중복 리스트로 넣기
my_iris = np.array([[5, 3.5, 1.4, 0.25], [6.7, 3.0, 5.2, 2.2]])
# 추론 : 모델.predict(추론할 데이터의 feature)
result = tree_model.predict(my_iris)
# 예측 결과
print(result)
print(iris.target_names[result])
[0 2]
['setosa' 'virginica']
ex) 추론결과를 확률로 반환해보자.
# index가 label
# [1, 0, 0] = > 0번꽃일 확률이 1, 1번,2번꽃일 확률은 0
# [0. , 0.02173913, 0.97826087] = > 2번 꽃일 확률이 확실하게 높다.
그러나, 위와 같은 프로세스를 거친 결과를 신뢰할 수 있나?
- 모델이 추론한 결과가 맞다는 것을 어떻게 보증할 수 있을까? 근거가 필요하다. 그래서 평가가 필요하다.
- 모델을 최종 서비스에 적용하기 전에 모델의 성능을 확인하는 작업이 필요하다.
그리고 평가를 위해서는 훈련 데이터셋과 테스트 데이터 분할 작업이 필요하다.
5. 훈련데이터셋과 평가(테스트)데이터 분할
- 위의 예는 우리가 만든 모델이 성능이 좋은 모델인지 나쁜 모델인지 알 수 없다.
- 전체 데이터 셋을 두개의 데이터셋으로 나눠
- 하나는 모델을 훈련(패턴 찾을)할 때 사용하고 => 훈련 데이터 셋
- 다른 하나는 그 모델을 평가할 때 사용한다. => 평가 데이터 셋
- 보통 훈련데이터와 테스트데이터의 비율은 8:2 또는 7:3 정도로 나누는데, 데이터셋이 충분하다면 6:4까지도 나눈다.
- 데이터셋 분할시 주의할 점
- 분류 문제의 경우, 각 클래스(분류대상)가 같은 비율로 나뉘야 한다. = > stratify = iris.target
- 만약, 0, 1, 2 분류 데이터(원본데이터)가 1:1:1 이라면,
나눠진 학습데이터와 테스트데이터들도 분류 데이터 간의 비율이 똑같아야 한다.
6. 머신러닝 프로세스
1. 데이터 셋 분리 : scikit-learn의 train_test_split() 함수를 이용해 iris 데이터셋 분할
- scikit-learn의 train_test_split() 함수 : 하나의 데이터를 두 세트로 분할하는 함수
- X_train, X_test, y_train, y_test => train F, test F, train L, test L
변수 : Feature - X , Label - y
훈련용 - train, 평가용 - test, 검증용 - val/validation (다음 ch에 배움)
- train_test_split() 매개변수
iris.data,
iris.target,
test_size = ,
random_state=0,
stratify = iris.target
1) 데이터 셋 분할
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(iris.data, # Feature - input - x
iris.target, # label(target) - output - y
test_size=0.2, # test set의 비율(train:0.8, test:0.2)
random_state=0, # random seed 값
stratify = iris.target) # class 별로 같은 비율로 나눠지도록 설정. (분류에서 필수!)
2) shape 확인
# feature (150,4) 을 (120,4), (30,4)으로 나눈 것
# label (150,) 을 (120,), (30,)으로 나눈 것.
X_train.shape, X_test.shape, y_train.shape, y_test.shape
((120, 4), (30, 4), (120,), (30,))
print(np.unique(y_train, return_counts=True)) # return_counts=True 갯수까지 열려줌
print(np.unique(y_test, return_counts=True))
print(np.unique(iris.target, return_counts=True))
(array([0, 1, 2]), array([40, 40, 40], dtype=int64))
(array([0, 1, 2]), array([10, 10, 10], dtype=int64))
(array([0, 1, 2]), array([50, 50, 50], dtype=int64))
2. 모델 생성
from sklearn.tree import DecisionTreeClassifier
tree_model = DecisionTreeClassifier(max_depth=2, random_state=0) # 함수 내부적으로 random한 값을 사용한다는 것을 알 수 있다.
3. 모델 학습
학습 fit : '기본공식' 을 '내 데이터셋' 에 맞추는 작업. = > 의사결정나무 객체에 iris 데이터에 맞추는 과정
= > 데이터에 맞춰 어떤 질문을 하는 것을 찾아내는 학습하는 과정
의사결정나무 알고리즘
# 답을 결정하기 위해 트리 구조를 만든다.
# 질문으로 노드에 하나의 클래스 값만 있게 나눈다. 계속적으로 질문하며 분류한다.
= = > fit(feature, label) == > train dataset X_train, y_train 을 이용해서 학습
tree_model.fit(X_train, y_train) # (input-X, output-y)
4. 예측
pred_train : Train dataset (Train할 때 사용한 데이터 셋) 의 Feature를 가지고 예측
pred_test : Test dataset (새로운 데이터 셋 - train 시 사용하지 않은 데이터 셋) 의 Feature를 가지고 예측
1) .predict(X_train) .predict(X_test) 예측
- 추론할 데이터의 feature 로 X_train 과 X_test 를 넣었다.
pred_train = tree_model.predict(X_train) # Train dataset의 Feature를 가지고 예측
pred_test = tree_model.predict(X_test) # Test dataset의 Feature를 가지고 예측
2) X_train 각각의 120개의 데이터에 대해서 pred_train 의 결과가 120개 나온다.
X_test 각각의 30개의 데이터에 대해서 pred_test 의 결과가 30개 나온다.
= > index로 확인 가능.
X_train.shape, pred_train.shape, X_test.shape, pred_test.shape
((120, 4), (120,), (30, 4), (30,))
print(X_train[:5]) # 훈련 데이터 셋
print('--------')
print(pred_train[:5]) # 훈련 데이터 셋 정확도. 학습데이터 예측 평가
print('--------')
print(y_train[:5]) # 정답 데이터
- 다섯 개 중에 다섯 개 다 맞음. 정확도 100%
[[4.8 3. 1.4 0.3]
[4.9 3. 1.4 0.2]
[4.4 3. 1.3 0.2]
[5. 3.4 1.5 0.2]
[5.8 2.7 3.9 1.2]]
--------
[0 0 0 0 1]
--------
[0 0 0 0 1]
5. 평가
- 머신러닝 평가지표 함수들은 sklearn.metrics 모듈에 있다.
- accuracy(정확도)
- 전체 데이터셋중 맞춘 개수의 비율
- '훈련데이터'와 '테스트 데이터' 두 가지를 평가 한다.
pred_train : Train dataset (Train할 때 사용한 데이터 셋) 의 Feature를 가지고 예측
pred_test : Test dataset (새로운 데이터 셋 - train 시 사용하지 않은 데이터 셋) 의 Feature를 가지고 예측
1) 평가 : 정확도 계산 함수를 통해 정확도 확인
- 평가지표 : 0 ~ 1 사이 실수
- 함수 : accuracy_score(정답, 예측한 결과)
from sklearn.metrics import accuracy_score
acc_train = accuracy_score(y_train, pred_train) # (정답, 예측한 결과)
acc_test = accuracy_score(y_test, pred_test)
print('훈련데이터셋 정확도: {}, 테스트데이터셋 정확도: {}'.format(acc_train, acc_test))
- 정확도가 1 이 아니다. 뭐가 틀렸는 지는 Confusion Matrix를 통해 확인한다.
훈련데이터셋 정확도: 0.9666666666666667, 테스트데이터셋 정확도: 0.9333333333333333
2) 평가 : 혼동행렬 (Confusion Matrix) 을 통해 확인
- 모델이 예측한 결과와 실제 정답간의 개수를 표로 제공
- 분류의 평가 지표로 사용된다.
- 함수 : confusion_matrix(정답, 예측한 결과)
- axis=0: 실제(정답)
axis=1: 예측
from sklearn.metrics import confusion_matrix
train_cm = confusion_matrix(y_train, pred_train) # (정답, 예측한 결과)
train_cm
# axis =0 : 예측 label 0,1,2
# axis=1 : 정답 label 0,1,2
# value : 예측한 갯수
# 답이 0인 40개의 데이터는 모두 예측 성공 하였다. / 답이 1인데 2로 예측한 게 1개 / 답이 2인데 1로 예측한 것이 3개
array([[40, 0, 0],
[ 0, 39, 1],
[ 0, 3, 37]], dtype=int64)
- pred_train_confusion_matrix 를 판다스 데이터 프레임으로
import pandas as pd
pred_train_cm = pd.DataFrame(train_cm, columns=[['예측', '예측', '예측'], iris.target_names], index=[['실제','실제','실제'], iris.target_names])
pred_train_cm
- pred_test_confusion_matrix 를 판다스 데이터 프레임으로
pred_test_cm = pd.DataFrame(test_cm, columns=[['예측', '예측', '예측'], iris.target_names], index=[['실제','실제','실제'], iris.target_names])
pred_test_cm
'AI_STUDY > 머신러닝' 카테고리의 다른 글
머신러닝 _ 06_2_파이프라인 (0) | 2022.07.09 |
---|---|
머신러닝 _ 06_1_과적합 일반화와 그리드 서치 (0) | 2022.07.06 |
머신러닝 _ 04_데이터 전처리 (0) | 2022.07.01 |
머신러닝 _ 03_데이터셋 나누기와 교차검증 (0) | 2022.06.30 |
머신러닝 _ 01 개요 (0) | 2022.06.27 |