4-3. Random Forest
In [1]:
from IPython.core.display import display, HTML
display(HTML("<style> .container{width:90% !important;}</style>"))

1. 배깅(Bagging)이란?

배깅(Bagging)은 Bootstrap Aggregating의 약자로, 보팅(Voting)과는 달리 동일한 알고리즘으로 여러 분류기를 만들어 보팅으로 최종 결정하는 알고리즘

**배깅은 다음과 같은 방식으로 진행이 됩니다.

(1) 동일한 알고리즘을 사용하는 일정 수의 분류기 생성
(2)각각의 분류기는 부트스트래핑(Bootstrapping)방식으로 생성된 샘플데이터를 학습
(3)최종적으로 모든 분류기가 보팅을 통헤 예측 결정

※ 부트스트래핑 샘플링은 전체 데이터에서 일부 데이터의 중첩을 허용하는 방식

2. 랜덤포레스트(RandomForest)

랜덤 포레스트는 여러 개의 결정트리(Decision Tree)를 활용한 배깅 방식의 대표적인 알고리즘

장점

  • 결정 트리의 쉽고 직관적인 장점을 그대로 가지고 있음
  • 앙상블 알고리즘 중 비교적 빠른 수행 속도를 가지고 있음
  • 다양한 분야에서 좋은 성능을 나타냄

단점

  • 하이퍼 파라미터가 많아 튜닝을 위힌 시간이 많이 소요됨

사용자 행동 데이터 세트를 이용한 RandomForest 예측

In [2]:
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

import warnings
warnings.filterwarnings('ignore')
In [3]:
# 데이터셋을 구성하는 함수 설정
def get_human_dataset():
    
    # 각 데이터 파일들은 공백으로 분리되어 있으므로 read_csv에서 공백문자를 sep으로 할당
    feature_name_df = pd.read_csv('human_activity/features.txt', sep='\s+',
                                                     header=None, names=['column_index', 'column_name'])
    # 데이터프레임에 피처명을 컬럼으로 뷰여하기 위해 리스트 객체로 다시 반환
    feature_name = feature_name_df.iloc[:, 1].values.tolist()
    
    # 학습 피처 데이터세트와 테스트 피처 데이터를 데이터프레임으로 로딩
    # 컬럼명은 feature_name 적용
    X_train = pd.read_csv('human_activity/train/X_train.txt', sep='\s+', names=feature_name)
    X_test = pd.read_csv('human_activity/test/X_test.txt', sep='\s+', names=feature_name)
    
    # 학습 레이블과 테스트 레이블 데이터를 데이터 프레임으로 로딩, 컬럼명은 action으로 부여
    y_train = pd.read_csv('human_activity/train/y_train.txt', sep='\s+', names=['action'])
    y_test = pd.read_csv('human_activity/test/y_test.txt', sep='\s+', names=['action'])
    
    # 로드된 학습/테스트용 데이터프레임을 모두 반환
    return X_train, X_test, y_train, y_test

# 학습/테스트용 데이터 프레임 반환
X_train, X_test, y_train, y_test = get_human_dataset()
In [4]:
# 랜덤 포레스트 학습 및 별도의 테스트 세트로 예측 성능 평가
rf_clf = RandomForestClassifier(random_state=0)
rf_clf.fit(X_train, y_train)
pred = rf_clf.predict(X_test)
accuracy = accuracy_score(y_test, pred)
print('랜덤 포레스트 정확도: {:.4f}'.format(accuracy))
랜덤 포레스트 정확도: 0.9108

3. 랜덤포레스트 하이퍼 파라미터 튜닝

랜덤포레스트는 트리기반의 하이퍼 파라미터에 배깅, 부스팅, 학습, 정규화 등을 위한 하이퍼 파라미터까지 추가되므로 튜닝할 파라미터가 많습니다.

파라미터 명 설명
n_estimators - 결정트리의 갯수를 지정
- Default = 10
- 무작정 트리 갯수를 늘리면 성능 좋아지는 것 대비 시간이 걸릴 수 있음
min_samples_split - 노드를 분할하기 위한 최소한의 샘플 데이터수
→ 과적합을 제어하는데 사용
- Default = 2 → 작게 설정할 수록 분할 노드가 많아져 과적합 가능성 증가
min_samples_leaf - 리프노드가 되기 위해 필요한 최소한의 샘플 데이터수
- min_samples_split과 함께 과적합 제어 용도
- 불균형 데이터의 경우 특정 클래스의 데이터가 극도로 작을 수 있으므로 작게 설정 필요
max_features - 최적의 분할을 위해 고려할 최대 feature 개수
- Default = 'auto' (결정트리에서는 default가 none이었음)
- int형으로 지정 →피처 갯수 / float형으로 지정 →비중
- sqrt 또는 auto : 전체 피처 중 √(피처개수) 만큼 선정
- log : 전체 피처 중 log2(전체 피처 개수) 만큼 선정
max_depth - 트리의 최대 깊이
- default = None
→ 완벽하게 클래스 값이 결정될 때 까지 분할
또는 데이터 개수가 min_samples_split보다 작아질 때까지 분할
- 깊이가 깊어지면 과적합될 수 있으므로 적절히 제어 필요
max_leaf_nodes 리프노드의 최대 개수
In [5]:
# RandomForest의 하이퍼 파라미터 default 상태
model = RandomForestClassifier()
model
Out[5]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators='warn', n_jobs=None,
            oob_score=False, random_state=None, verbose=0,
            warm_start=False)

GridSearchCV를 통한 랜덤포레스트의 하이퍼 파라미터 튜닝

In [6]:
from sklearn.model_selection import GridSearchCV

params = { 'n_estimators' : [10, 100],
           'max_depth' : [6, 8, 10, 12],
           'min_samples_leaf' : [8, 12, 18],
           'min_samples_split' : [8, 16, 20]
            }

# RandomForestClassifier 객체 생성 후 GridSearchCV 수행
rf_clf = RandomForestClassifier(random_state = 0, n_jobs = -1)
grid_cv = GridSearchCV(rf_clf, param_grid = params, cv = 3, n_jobs = -1)
grid_cv.fit(X_train, y_train)

print('최적 하이퍼 파라미터: ', grid_cv.best_params_)
print('최고 예측 정확도: {:.4f}'.format(grid_cv.best_score_))
최적 하이퍼 파라미터:  {'max_depth': 12, 'min_samples_leaf': 8, 'min_samples_split': 8, 'n_estimators': 100}
최고 예측 정확도: 0.9206
In [7]:
#위의 결과로 나온 최적 하이퍼 파라미터로 다시 모델을 학습하여 테스트 세트 데이터에서 예측 성능을 측정
rf_clf1 = RandomForestClassifier(n_estimators = 100, 
                                max_depth = 12,
                                min_samples_leaf = 8,
                                min_samples_split = 8,
                                random_state = 0,
                                n_jobs = -1)
rf_clf1.fit(X_train, y_train)
pred = rf_clf1.predict(X_test)
print('예측 정확도: {:.4f}'.format(accuracy_score(y_test,pred)))
예측 정확도: 0.9230

Random Forest의 각 피처의 중요도 시각화 : featureimportances

In [8]:
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

ftr_importances_values = rf_clf1.feature_importances_
ftr_importances = pd.Series(ftr_importances_values, index = X_train.columns)
ftr_top20 = ftr_importances.sort_values(ascending=False)[:20]

plt.figure(figsize=(8,6))
plt.title('Top 20 Feature Importances')
sns.barplot(x=ftr_top20, y=ftr_top20.index)
plt.show()
  1. 익명 2021.08.18 14:33

    비밀댓글입니다

Frank Rosenblatt가 인간 두뇌의 뉴런을 계산모델로서 퍼셉트론(Perceptron)이라는 개념을 제시함.
그는 퍼셉트론이 간단한 함수, 최근에 우리가 부르는 이진분류(Binary Classification)를 학습할 수 있음을 보여주었음.
하나의 층의 퍼셉트론은 최근에 이야기 되는 뉴럴 네트워크의 가장 간단한 형태의 신경망으로 볼 수 있음.

퍼셉트론에서 단일 계층에 입력되는 인풋과 가중합이 수행되며, 이 가중합은 뉴런 안에 내재된 활성함수(Activation Function)를 통과하게 됩니다. 이 때 활성함수가 반환한 것을 임계값과 비교하여 각 데이터가 속하는 클래스를 결정.

오류는 집계되어 합계를 구하는데 사용되는 가중치를 변경하며, 프로세스는 결과가 수렴할 때까지 계속 반복함.

인간 두뇌의 가장 기본적인 단위는 뉴런으로 뉴럴네트워크는 서로 다른 패턴과 구조로 연결된 뉴런들의 집합임.
위의 그림은 뉴런의 구조를 나타낸 것.

  • Dendrite : 입력 신호(외부자극)을 수신하는 부분
  • Nucleus : 수용된 여러개의 외부 자극을 새로운 자극으로 가공
  • Axon : 새로운 자극이 myelin sheath의 보조를 받아 Axon을 거쳐 여러 가닥으로 송출됨. 이 때 각 가닥은 다른 뉴런의 Dendrite와 연결되어 있음.

이 그림은 뉴런을 수학적으로 나타낸 그림으로 위에 제시된 뉴런의 색과 매칭해보면
인풋이 입력되서 아웃풋으로 송출되기까지의 과정을 알 수 있음

여러 인풋들이 입력되어 가중치를 곱하고 합해집니다. 그 이후 이 값을 임계값과 비교하여 활성함수에 의해 변형됨.
정해진 임계치와 비교해서 값이 의미가 있으면 활성화되고, 아니면 활성화되지 못함.

좋은 아이디어이지만 이 퍼셉트론은 XOR함수같은 복잡한 함수를 모델링하지는 못함.
때문에 처음에는 퍼셉트론 개념이 잘 받아들여지지 않았지만,
후에는 인공신경만, 딥러닝 모델링을 위한 기본 단위로 활용됨.

Sir Francis Galton이 자연현상을 측정하기 위해 통계적인 방법을 활용하며 선형회귀를 고안하였음
(위의 도표는 최초의 선형회귀에 대한 그래프)

콩의 부모와 자식간의 상대적 크기에 대한 데이터를 살펴보던 중 특이한 점을 발견하였음
부모가 크면 클 수록 자식의 크기 또한 커지는 경향을 발견함.
그렇다면 그 세대 내에서 그 자식세대는 다른 자식세대에 비해 얼마나 클 것인가?
자식세대의 크기 차이 비율은 부모세대의 크기 차이 비율보다는 상대적으로 낮게 나타났음.
가령 부모의 크기가 평균보다 1.5표준편차만큼 크다면, 자식세대는 1.5표준편차보다는 작게 큼.
결국 평균으로 회귀를 하는 모습을 보였고 이러한 특성으로 인해 Linear Regression 이라는 명칭으로 불리게 됨
그리고 컴퓨팅 파워가 발전하면서 이런 현상이 큰 데이터셋에도 잘 적용됨을 알게됨

위의 식은 일반화된 회귀모델을 수식으로 표현한 것으로 피처(x)들과 가중치(w)를 곱한 것들의 합(y)으로 나타난다.
이 식을 우리가 가진 데이터 셋의 모든 행에 적용함으로서 예측값을 만들어낼 수 있음.
이 식의 형태는 선형회귀 뿐만 아니라 딥러닝의 신경망 네트워크 등에 있어서도 매우 중요함.

그러면 예측된 값 좋은지 나쁜지 어떻게 알 수 있을까?
→ 손실함수(Loss function)을 적용해서 알 수 있다.

회귀문제에서 주로 사용되는 손실함수는 MSE이다.
위의 식은 L2 Norm이라는 것을 계산하는 식으로 실제 값(y)에서 예측된 값(Xw)의 차이를 기반으로 손실을 계산한다.

머신러닝 모델을 최적화시킬 때, 손실함수가 계산한 손실값이 최소화되는 지점을 찾아내야 한다.
이를 위해 가중치를 조정해가며 모델의 손실값이 최소화되는 지점을 발견해야 함.

그러면 가중치 값을 어떻게 조절해야 손실값을 최소화할 수 있는가?
선형회귀에서는 위와 같은 식이 존재함.
하지만 이는 실용적이지 못함. 중복성 데이터에 대한 고려가 없고, 시간도 오래 걸림.

위의 방법 대신, 경사하강법(Gradient Descent)을 적용할 수 있는데,
다음과 같은 이점있음

  1. 비교적 낮은 시간과 공간 복잡도
  2. 일반화가 더 잘됨
  3. 대부분의 문제에도 활용이 가능함

위의 그래프는 세 개 가중치 파라미터에 대한 3차원 형태의 손실값 공간으로
산과 계곡처럼 굴곡진 형태로 표현이 됨.

경사하강법에서는 위의 평면 어디에서 시작을 하던지 내려가는 경사를 따라가며, 제일 낮은 지점을 찾아간다.
그 지점이 손실이 최소화되는 지점(Global Minimum)임.

경사하강으로 얻어진 정보(방향/경사도)를 이용해서, 한 번에 하강할 보폭의 크기를 결정해야하는데,
그 정도를 학습률(learning rate)이라고 한다.

5. Handling Missing Data(결측치 다루기)
In [1]:
from IPython.core.display import display, HTML
display(HTML("<style> .container{width:90% !important;}</style>"))

Handling Missing Data

In [2]:
import pandas as pd
import numpy as np
In [3]:
# 임의의 데이터프레임 생성
df = pd.DataFrame( [ [np.nan, 2, np.nan, 0], 
                     [3, 4, np.nan, 1],
                     [np.nan, np.nan, np.nan, 5] ],
                                 columns = list('ABCD') )
df
Out[3]:
A B C D
0 NaN 2.0 NaN 0
1 3.0 4.0 NaN 1
2 NaN NaN NaN 5

dropna(axis = ?, how = ?, inplace = ?) : 결측치 버리기

  • axis = 0 (default) : 행 버리기 ⟷ axis = 1 : 컬럼 버리기
  • how = 'any' (default) : 행 또는 열의 NaN이 하나라도 있을 때 버리기 ⟷ how = 'all' : 전체 행 또는 열의 값이 NaN일 때 버리기
  • inplace = False (default) : drop한 결과 조회만 하기 ⟷ inplace = True : drop한 결과 데이터프레임에 바로 저장
In [4]:
# 전부다 Null인 컬럼 drop
df.dropna(axis=1, how= 'all') 
Out[4]:
A B D
0 NaN 2.0 0
1 3.0 4.0 1
2 NaN NaN 5
In [5]:
# 하나라도 Null이 있는 컬럼 drop
df.dropna(axis=1, how= 'any') 
Out[5]:
D
0 0
1 1
2 5
In [6]:
# 전부다 Null인 열 drop
df.dropna(axis=0, how='all')
Out[6]:
A B C D
0 NaN 2.0 NaN 0
1 3.0 4.0 NaN 1
2 NaN NaN NaN 5
In [7]:
# 하나라도 Null이 있는 열 drop
df.dropna(axis=0, how='any')
Out[7]:
A B C D


df.fillna : NaN 을 지정해준 값으로 채워줌

In [8]:
# 결측치 0으로 채우기
df.fillna(0)
Out[8]:
A B C D
0 0.0 2.0 0.0 0
1 3.0 4.0 0.0 1
2 0.0 0.0 0.0 5
In [9]:
# 딕셔너리를 사용해서 컬럼별로 지정값으로 채우기
values = { 'A' : 0, 'B': 1, 'C': 2, 'D': 3}
df.fillna(value=values)
Out[9]:
A B C D
0 0.0 2.0 2.0 0
1 3.0 4.0 2.0 1
2 0.0 1.0 2.0 5
In [10]:
# 결측치를 중앙값으로 채우기
fill_na_value = df['D'].median()
df.fillna(fill_na_value)
Out[10]:
A B C D
0 1.0 2.0 1.0 0
1 3.0 4.0 1.0 1
2 1.0 1.0 1.0 5
In [11]:
# 컬럼별로 결측치 데이터 갯수 확인
df.isnull().sum() 
Out[11]:
A    2
B    1
C    3
D    0
dtype: int64
In [12]:
# 컬럼별로 결측치가 아닌 데이터 갯수 확인
df.notnull().sum()
Out[12]:
A    1
B    2
C    0
D    3
dtype: int64
4. Summarize Data(자료 요약하기)
In [1]:
from IPython.core.display import display, HTML
display(HTML("<style> .container{width:90% !important;}</style>"))

Summarize Data

In [2]:
import pandas as pd
import seaborn as sns
import numpy as np
In [3]:
# 예제 데이터셋 불러오기
df = sns.load_dataset('iris')
df.shape
Out[3]:
(150, 5)
In [4]:
df.head()
Out[4]:
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
In [5]:
# 카테고리형 변수가 각 값별로 데이터가 얼마나 있는지 확인
df['species'].value_counts() 
Out[5]:
virginica     50
setosa        50
versicolor    50
Name: species, dtype: int64
In [6]:
# value_counts() 한 것을 데이터 프레임으로 넣기
df['species'].value_counts().to_frame()
# pd.DataFrame(df['species'].value_counts()) 도 같은 결과
Out[6]:
species
virginica 50
setosa 50
versicolor 50
In [7]:
# 데이터 프레임의 행수 확인
len(df)
# df.shape[0] 도 같은 결과
Out[7]:
150
In [8]:
# 변수의 유니크한 값 개수
df['species'].nunique() 
Out[8]:
3
In [9]:
# describe()를 사용해서 기본 통계값들을 확인할 수 있다.
df.describe()
Out[9]:
sepal_length sepal_width petal_length petal_width
count 150.000000 150.000000 150.000000 150.000000
mean 5.843333 3.057333 3.758000 1.199333
std 0.828066 0.435866 1.765298 0.762238
min 4.300000 2.000000 1.000000 0.100000
25% 5.100000 2.800000 1.600000 0.300000
50% 5.800000 3.000000 4.350000 1.300000
75% 6.400000 3.300000 5.100000 1.800000
max 7.900000 4.400000 6.900000 2.500000
In [10]:
# include = 'all' 인자를 넣어주면 categorical 변수에 대한 값인 unique, top, freq도 조회할 수 있음
df.describe(include='all')
Out[10]:
sepal_length sepal_width petal_length petal_width species
count 150.000000 150.000000 150.000000 150.000000 150
unique NaN NaN NaN NaN 3
top NaN NaN NaN NaN virginica
freq NaN NaN NaN NaN 50
mean 5.843333 3.057333 3.758000 1.199333 NaN
std 0.828066 0.435866 1.765298 0.762238 NaN
min 4.300000 2.000000 1.000000 0.100000 NaN
25% 5.100000 2.800000 1.600000 0.300000 NaN
50% 5.800000 3.000000 4.350000 1.300000 NaN
75% 6.400000 3.300000 5.100000 1.800000 NaN
max 7.900000 4.400000 6.900000 2.500000 NaN
In [11]:
# 문자형(카테고리형) 변수에 대한 통계값을 조회할 수 있음
df.describe(include=[np.object])
Out[11]:
species
count 150
unique 3
top virginica
freq 50
In [12]:
# 수치형 변수에 대한 통계값을 조회할 수 있음
df.describe(include=[np.number])
Out[12]:
sepal_length sepal_width petal_length petal_width
count 150.000000 150.000000 150.000000 150.000000
mean 5.843333 3.057333 3.758000 1.199333
std 0.828066 0.435866 1.765298 0.762238
min 4.300000 2.000000 1.000000 0.100000
25% 5.100000 2.800000 1.600000 0.300000
50% 5.800000 3.000000 4.350000 1.300000
75% 6.400000 3.300000 5.100000 1.800000
max 7.900000 4.400000 6.900000 2.500000
In [13]:
# 해당 컬럼의 값 합계
df['petal_width'].sum()
Out[13]:
179.90000000000003
In [14]:
# 해당 컬럼의 null이 아닌 행의 수
df['petal_width'].count()
Out[14]:
150
In [15]:
# 해당 컬럼의 중위수
df['petal_width'].median()
Out[15]:
1.3
In [16]:
# 해당 컬럼의 평균값
df['petal_width'].mean()
Out[16]:
1.199333333333334
In [17]:
# 데이터 프레임 각 컬럼의 평균값
df.mean()
Out[17]:
sepal_length    5.843333
sepal_width     3.057333
petal_length    3.758000
petal_width     1.199333
dtype: float64
In [18]:
# 4분위수 확인하기
df.quantile([0.25, 0.75])
Out[18]:
sepal_length sepal_width petal_length petal_width
0.25 5.1 2.8 1.6 0.3
0.75 6.4 3.3 5.1 1.8
In [19]:
# 데이터 프레임 각 컬럼의 최댓값
df.max()
Out[19]:
sepal_length          7.9
sepal_width           4.4
petal_length          6.9
petal_width           2.5
species         virginica
dtype: object
In [20]:
# 데이터 프레임 각 컬럼의 최솟값
df.min()
Out[20]:
sepal_length       4.3
sepal_width          2
petal_length         1
petal_width        0.1
species         setosa
dtype: object
In [21]:
# 데이터 프레임 각 컬럼의 분산
df.var()
Out[21]:
sepal_length    0.685694
sepal_width     0.189979
petal_length    3.116278
petal_width     0.581006
dtype: float64
In [22]:
# 데이터 프레임의 각 컬럼의 표준편차
df.std()
Out[22]:
sepal_length    0.828066
sepal_width     0.435866
petal_length    1.765298
petal_width     0.762238
dtype: float64

apply(function)

In [23]:
# 임의의 함수 설정
def smp(x):
    # 뒤에서 세번째까지의 문자를 가져오는 함수
    x = x[-3:]
    return x 
In [24]:
# lambda 익명함수 적용
df['species_3'] = df['species'].apply(lambda x : x[:3]) 
In [25]:
# 설정해둔 함수 적용
df['species_4'] = df['species'].apply(smp) 
In [26]:
df.head()
Out[26]:
sepal_length sepal_width petal_length petal_width species species_3 species_4
0 5.1 3.5 1.4 0.2 setosa set osa
1 4.9 3.0 1.4 0.2 setosa set osa
2 4.7 3.2 1.3 0.2 setosa set osa
3 4.6 3.1 1.5 0.2 setosa set osa
4 5.0 3.6 1.4 0.2 setosa set osa

위의 그래프는 팁 금액을 레이블로 한 ML 모델의 예시

(계산금액와 성별은 이를 추정하기 위한 피처)

 

여기서 팁 금액은 연속형이기 때문에, 회귀문제에 해당함

회귀문제에서는 피쳐들의 조합으로 이루어진 수학적인 함수를 이용하여 레이블 값을 예측하는 것

모델이 위 그래프에서 초록색 선으로 계산금액과 선의 기울기의 곱으로 레이블 값을 구한다.

 

하나가 아닌 여러 개의 피처를 이용하는 다차원의 문제에서도 개념은 동일함

각 개별 데이터의 피처 값에 하이퍼플레인(Hyperplane)의 기울기가 곱해지면서,

레이블의 일반화된 값을 구한다.

(※ 하이퍼플레인(Hyperplane)은 1차원 이상 공간에서의 모델링된 평면을 이야기함)

 

선형회귀 문제에서는 모델을 일반화하기 위해 예측된 값들과 레이블 값의 거리(에러)를 최소화하려고 함.

이 때 자주 사용되는 것이 MSE(Mean Squared Error)이다.

 

위의 예시에서 성별을 레이블로, 계산금액과 팁 금액을 피쳐로 분류 문제가 된다.

하지만 이 경우 남성과 여성의 관측값이 잘 분리 되어 있지 않기 때문에 좋은 접근은 아님.

 

분류 문제에서는 레이블의 연속적인 값을 구하는 것이 아니라 각각 레이블 값을 나누는

결정 경계(decision boundary)를 만들려고 한다.

이 경우 클래스 값이 두개가 존재하고, 결정경계는 차원에 따라 선이나 하이퍼플레인으로 만들어짐.

위의 예시에서는 빨간 선이 결정 경계임.

 

 

 

분류문제에서는 예측 클래스와 레이블 클래스 간의 에러를 최소화하기 위해

Cross Entropy(Log Loss)를 사용한다.

여기서 N은 데이터 갯수, M은 레이블 갯수,

y는 정답(0또는 1)을 나타내며 p는 예측값의 확률(0~1)사이

예측 값이 맞을 경우 log1 이 되기 되고 틀린 값으로 예측할수록 Cross Entropy의 값은 높아짐

 

하지만 팁 금액을 측정하는 경우라도, 반드시 회귀문제가 되는 것은 아님. 팁 크기를 범주화해서

25%~ 일 때는 "High" , 15 ~ 25% 일 때는 "Average", ~15% 일 때는 "Low" 로 만든다면

분류 문제가 될 수 있다.

 

그 반대의 경우로 카테고리형의 피처도 연속형으로 변경될 수 있다.

 

결국 어떻게 문제를 해결하려고 하는지에 달려있는 것으로, 

머신러닝은 결국 실험에 관한 것이다.

 

 

그렇다면 머신러닝에 이용하는 데이터는 어디에서 오는가?

 

앞의 팁 데이터셋은 흔히 행과 열로 표현되는 "구조화된" 데이터이다.

(흔히 DB에서 조회하는 테이블 같은 것)

머신러닝에서 흔히 사용되는 구조화된 데이터는 Data Warehouse에서 나옴.

 

"비구조화"된 데이터는 사진, 오디오와 비디오 등과 같은 것.

 

위의 표는 출생에 관한 공개 데이터 셋으로 빅쿼리에서 제공됨.

SQL을 통해 구조화 데이터를 불러오고, mother_age와 gestation_weeks 등의 피쳐를 활용하고,

모델을 생성하여 아이가 언제 태어날 지를 회귀 문제로 예측할 수 있음

이 외에도 아이 몸무게 등을 레이블로 설정하여 여러 값을 예측할 수 있다.

 

 

위의 데이터셋은 선형회귀와 분류 모두에 적합한 형태를 띄고 있다.

 

 

위의 빨간선과 파란선은 Class A와 Class B의 x와 y에 대한 모델이 된다. 

하지만 이를 모두 아우르는 일반적인 모델을 얻고자 한다면 초록색 선이 일반화된 모델로

MSE에 의해 모델의 예측값과 실제 값 사이의 손실이 최소화되는 선이다.

 

 

 

빨간색과 파란색을 아우르는 모델을 도출하기 위해 여러 피처를 사용해서 더 고차원 적으로 접근할 수 있음.

그 경우 위의 그림에서처럼 2d 선형회귀의 결과인 하이퍼플레인이 만들어진다.

이 때, 이 2차원인 하이퍼플레인은 빨간 선과 파란 선, 그리고 그 중간의 초록색 선까지 모두 포괄한다.

 

 

 

동일한 예시를 분류문제로 보았을 때, Class A와 Class B 를 구분하는 선은 노란선이다.

이 경우 회귀에서 사용한 초록선과 일치하지 않는다.

 

그 이유는 무엇일까?

회귀모델에서의 손실함수는 MSE가 사용되었지만, 분류모델의 손실함수는 Cross Entropy이기 때문

MSE의 경우 예측값과 실제값 사이의 거리차를 제곱하지만, Cross Entropy의 경우 두 값의 차이가 클수록

기하급수적으로 손실이 늘어나는 차이가 존재한다.

[Supervised Learning]  

 

머신러닝은 크게 지도학습(Supervised Learning)과 비지도학습(Unsupervised Learning)으로 나뉨.

 

이 지도학습과 비지도학습의 큰 차이는 예측하고자 하는 것에 대한 정답, 레이블(Label)의 존재 유무이다.

지도학습의 경우에는 레이블이 존재하지만, 비지도학습에서는 존재하지 않는다.

사람이 만들어 놓은 정답지로 모델이 나아가야 할 방향을 지도할지 말지 차이가 두 방법론의 차이

좌측 그래프는 Income(소득)과 Years at Company(재직기간)의 관계를 나타냄

비지도 학습을 통해 소득과 재직기간을 클러스터링하여 누가 빠르게 승진하고 있는지 알아보려고 할 때,

비지도 학습 알고리즘은 근거(정답)없이 관찰을 통해 스스로 기준을 학습하여 두 가지 그룹으로 나누게 됨

 

 

지도학습은 각 데이터 포인트의 레이블에 대한 개념이 존재하고 있음

 

위의 예시는 식당에서 웨이터의 성별, 계산금액, 팁금액에 대한 과거 데이터로

이를 기반으로 팁 금액이나 성별 등을 예측하는 모델을 만들려고 함

이 경우 과거 데이터의 팁 금액과 성별이 레이블에 해당함.

 

그런 다음 내역 데이터와 특정 테이블에 대해 알고있는 값을 기반으로 팁을 실시간으로 예측하려고 함

지도학습의 경우 크게 두 가지 종류의 모델이 존재함  

 - 회귀모델 (Regression) : 팁과 같이 레이블의 값이 연속적일 경우의 문제

 - 분류모델 (Classification) : 성별과 같이 레이블의 값이 이산적으로 나뉠 수 있는 문제

 

그리고 위와 같은 데이터 셋에서 각 열의 명칭을 Feature라고 하며

각 행을 Example Data 라고 함

 

그리고 각 컬럼들 중에 예측하고자 하는 대상이 되는 컬럼이 레이블이 됨

머신러닝 문제의 유형은 레이블된 데이터를 가지고 있는지,

그리고 무엇을 예측하고자 하는지에 따라 달라진다.

이번 강좌를 통해 배울 수 있는 것들의 소개

 

- 머신러닝 기본 지식 습득을 통한 관련 용어의 이해

- 다양한 종류의 머신러닝 모델 

- 머신러닝 모델 역사를 통해 왜 현재의 딥러닝 모델이 인기가 있는지

- 손실함수(loss function)를 이용한 모델 최적화

- 성능지표(performance metrics)를 활용한 모델 평가

- 머신러닝에서 발생하는 일반적인 문제들과 이를 어떻게 완화하는지

 

 

※ Introdiction into qwiklabs 및 Introduction to Pratical ML 내용은 생략

+ Recent posts