728x90

* 결정트리 Decision Tree

 - 스무고개와 같이 질문을 하나씩 던져 정답을 맞춰가며 학습하는 알고리즘 -> 예측 과정을 이해하기 쉬움

* 검증세트 Validation set

 - hiperparameter 튜닝을 위해 모델을 평가할 때, test set을 사용하지 않기 위해 훈련 세트에서 다시 떼어낸 data set

* 교차검증 cross validation

 - 훈련세트를 여러 폴드로 나눈 다음 한 폴드가 검증 세트의 역할을 하고 나머지 폴드에서는 모델을 훈련

* 그리드 서치 Grid Search

 - hiperparameter 탐색을 자동화 해주는 도구 -> 자동으로 맞는 값을 찾아준다

* 랜덤 서치 Random Search

 - 연속적인 parameter의 값을 탐색할 때 유용

* 정형데이터(structured data) vs 비정형데이터(unstructured data)

 - CSV, database등 특정 구조로 되어 있는 것은 structed data, 정형화가 어려운 사진, 음악 등은 비정형 데이터라고 함

* 앙상블 학습 ensemble learning

 - 여러 알고리즘을 합쳐 성능을 높이는 머신러닝 기법

* 랜덤 포레스트 Random Forest

 - 대표적인 앙상블 학습 방법, 안정적인 성능

 - 부트스트랩 샘플 사용, 랜덤하게 일부 특성을 선택하여 트리를 만든다

* 부트스트랩 샘플 Bootstrap sample

 - 데이터세트에서 중복을 허용하여 데이터를 샘플링하는 방식

* 엑스트라 트리 extra trees

 - random forest와 비슷하게 동작하며 결정 트리를 사용하여 앙상블 모델을 만들지만 bootstrap sample을 사용하지 않는 대신 랜덤하게 노드를 분할하여 과대적합을 감소

* 그레이디언트 부스팅 Gradient boosting

 - 깊이가 얕은 결정 트리를 사용하여 이전 트리의 오차를 보완하는 방식으로 앙상블하는 방법, 깊이가 얕은 결정 트리를 사용하기 때문에 과대적합에 강하고 일반적으로 높은 일반화 성능을 기대할 수 있음

* Histogram-based Gradient Boosting

 - Gradient boosting의 속도를 개선한 것으로 과대적합을 잘 억제하며 Gradient boosting

728x90
728x90

차원 축소:

원본 데이터의 특성을 적은 수의 새로운 특성으로 변환하는 비지도 학습. 저장 공간을 줄이고 시각화 하기 좋음, 다른 알고리즘의 성능 향상

주성분 분석(Principal Component Analysis : PCA):

데이터에서 가장 분산이 큰 방향을 찾는 방법.( 이 방향을 주성분이라 한다) 일반적으로 주성분은 원본 데이터에 있는 특성 개수보다 작다.

설명된 분산:

주성분 분석에서 주성분이 얼마나 원본 데이터의 분산을 잘 나타내는지 기록한 것. 사이킷런의 PCA class는 주성분 개수나 설명된 분산의 비율을 지정하여 주성분 분석을 수행할 수 있다.

 

* 이미지를 예로 들면 모든 픽셀이 특성이 되는데 이를 모두 기록하기는 어렵다. 이들 특성 중 주성분을 분석하여 분산에 맞게 저장하는 방법을 학습한다. 또한 이렇게 저장된 내용으로 다시 원본 데이터에 가깝게 복구가 가능하다.

* 분산이 크다는 것은 data가 가장 멀리 퍼진 방향을 나타낸다. 점들이 직선에 가깝게 퍼져 있다면 이러한 직선이 data의 특성을 잘 나타낸다고 볼 수 있다.

 

PCA Class

!wget https://bit.ly/fruits_300_data -O fruits_300.npy
import numpy as np

fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)

from sklearn.decomposition import PCA

pca = PCA(n_components=50)
pca.fit(fruits_2d)

PCA(n_components=50)

PCA가 찾은 주성분이 componenctes_에 들어가 있다.

print(pca.components_.shape)

(50, 10000)

배열의 차원이 50이다.(주성분 50)

import matplotlib.pyplot as plt

def draw_fruits(arr, ratio=1):
    n = len(arr)    # n은 샘플 개수입니다
    # 한 줄에 10개씩 이미지를 그립니다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산합니다. 
    rows = int(np.ceil(n/10))
    # 행이 1개 이면 열 개수는 샘플 개수입니다. 그렇지 않으면 10개입니다.
    cols = n if rows < 2 else 10
    fig, axs = plt.subplots(rows, cols, 
                            figsize=(cols*ratio, rows*ratio), squeeze=False)
    for i in range(rows):
        for j in range(cols):
            if i*10 + j < n:    # n 개까지만 그립니다.
                axs[i, j].imshow(arr[i*10 + j], cmap='gray_r')
            axs[i, j].axis('off')
    plt.show()
draw_fruits(pca.components_.reshape(-1, 100, 100))

주성분을 50으로 잡았으니 특성의 개수를 10,000에서 50으로 줄일 수 있다.

transform()을 이용하여 원본 데이터의 차원을 50으로 줄일 수 있다.

print(fruits_2d.shape)
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape)

(300, 10000)

(300, 50)

 

원본 데이터 재구성

fruits_inverse = pca.inverse_transform(fruits_pca)
print(fruits_inverse.shape)
fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100)

for start in [0, 100, 200]:
    draw_fruits(fruits_reconstruct[start:start+100])
    print("\n")

줄어든 특성을 이용하여 다시 원본 데이터를 복구하였는데 거의 비슷한 결과를 볼 수 있다.

미분 후 적분한 것처럼 손실은 있다.

설명된 분산

print(np.sum(pca.explained_variance_ratio_))
plt.plot(pca.explained_variance_ratio_)
plt.show()

0.9214965686302707

50개의 주성분이 있으나 처음 10개의 주성분이 대부분의 분산을 표현하고 있다.

다른 알고리즘과 함께 사용하기

from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()

target = np.array([0] * 100 + [1] * 100 + [2] * 100)

from sklearn.model_selection import cross_validate

scores = cross_validate(lr, fruits_2d, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))

0.9966666666666667 : test score

1.5750249862670898 : fit time

scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))

1.0 : 50개의 주성분으로 분석했을 때 정확도가 100%로 나왔다

0.025466299057006835 : fit time 역시 엄청 줄었다.

pca = PCA(n_components=0.5)
pca.fit(fruits_2d)

PCA(n_components=0.5)

처음에는 주성분의 개수를 50개로 지정했는데 분산의 50%가 채워질 때까지 주성분의 개수를 늘리도록 변경하였다.

이렇게 변경한 다음 주성분의 개수가 몇개나 필요한 지 확인해보자.

print(pca.n_components_)

2

두개의 주성분이면 충분하다고 한다.

fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape)

(300, 2)

scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))

0.9933333333333334 : test score

0.036731719970703125 : fit time

특성을 두개만 사용해도 99.3%의 정확도를 나타낸다.

from sklearn.cluster import KMeans

km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_pca)

KMeans(n_clusters=3, random_state=42)

print(np.unique(km.labels_, return_counts=True))

(array([0, 1, 2], dtype=int32), array([110, 99, 91]))

for label in range(0, 3):
    draw_fruits(fruits[km.labels_ == label])
    print("\n")

for label in range(0, 3):
    data = fruits_pca[km.labels_ == label]
    plt.scatter(data[:,0], data[:,1])
plt.legend(['apple', 'banana', 'pineapple'])
plt.show()

두개만 가지고 분류했는데 분산이 잘 이루어져 있다.

파인애플과 사과는 경계가 거의 붙어있어 혼동이 있을 수 있다.

(그런데 바나나는 왜 섞여 들어간거지?)

728x90
728x90

* 다중 분류 : Multi-class classification

  - target data에 2개 이상의 class가 포함된 문제

* 로리스틱 회귀: logistic regression

   - 선형 방정식을 사용한 분류 알고리즘으로 선형 회귀와 달리 sigmoid function이나 softmax 함수를 사용하여 클래스 확률 출력

* sigmoid function

  - logistic regression이라고 부르기도 하며 선형 방정식의 출력을 0과 1사이의 값으로 압축하여 이진 분류를 위해 사용.

  - binary 분류일 경우 sigmoid function의 출력이 0.5보다 크면 양성, 작으면 음성으로 판단

* boolean indexing

  - 넘파이 배열은 True, False를 전달하여 행을 선택할 수 있음

* Softmax function

  - 여러개의 선형 방정식의 출력값을 0~1사이로 압축, 전체 합이 1이 되도록 만든다. 이를 위해 지수 함수를 사용하기 때문에 정규화된 지수 함수라고도 함

* 확률적 경사 : Stochastic Gradient Descent

  : 하강법 : 훈련 세트에서 랜덤하게 하나의 샘플을 선택하여 손실 함수의 경사를 따라 최적의 모델을 찾는 알고리즘

  : 에포크 : epoch : 확률적 경사 하강법에서 훈련세트를 한번 모두 사용하는 과정

 

* 미니배치 경사 : minibatch gradient descent

  : 하강법 : 1개가 아닌 여러 개의 샘플을 사용해 경사 하강법을 수행하는 방법으로 실전에서 많이 사용

* 배치 경사 하강법 : batch gradient descent

  - 한번에 전체 샘플을 사용하는 방법으로 전체 데이터를 사용하므로 가장 안정적인 방법이지만 그만큼 컴퓨터 자원을 많이 사용. data가 너무 많아 한번에 처리되지 않을 수 도 있음

 

* 손실함수 : loss function

  - 어떤 문제에서 머신러닝 알고리즘이 얼마나 엉터리인지 측정하는 기준

* 로지스틱 손실함수 : logistic loss function

  - 양성 클래스(target=1)일 때 손실은 -log(예측 확률)로 계산하며, 1 확률이 1에서 멀어질수록 손실은 아주 큰 양수가 됨. 음성 클래스(target=0)일 때 손실은 -log(예측 확률)로 계산. 이 예측 확률이 0에서 멀어질수록 손실은 아주 큰 양수가 됨

 

*크로스엔트로피 손실함수 : cross-entropy loss function

  : 손실함수 : 다중 분류에서 사용하는 손실 함수

* 힌지 손실 : hinge loss

  : support vector machine이라 불리는 머신러닝 알고리즘을 위한 손실 함수로 널리 사용하는 알고리즘 중 하나. SGDClassifier가 여러종류의 손실 함수를 loss 매개변수에 지정하여 다양한 머신러닝 앝고리즘을 지원함.

 

728x90
728x90
inertia = []
for k in range(2, 7):
    km = KMeans(n_clusters=k, random_state=42)
    km.fit(fruits_2d)
    inertia.append(km.inertia_)

plt.plot(range(2, 7), inertia)
plt.xlabel('k')
plt.ylabel('inertia')
plt.show()

k-평균(k-means): 처음에 랜덤하게 클러스터 중심을 정하고 클러스트를 만든다. 클러스터 중심을 이동하고 다시 클러스트 만들기를 반복하여 최적의 클러스터 구성하는 알고리즘

클러스터 중심(cluster center, centroid): k-평균 알고리즘이 만든 클러스터에 속한 샘플의 특성 평균 값. 가장 가까운 클러스터 중심을 샘플의 또 다른 특성으로 사용하거나 새로운 샘플에 대한 예측으로 활용 가능

엘보우 방법(elbow): 최적의 클러스터 개수를 정하는 방법 중 하나. 이너셔(inertia)는클러스터 중심과 샘플 사이 거리의 제곱 합. 클러스터 개수에 따라 이너셔 감소가 꺽이는 지점이 적절한 클러스터 개수 k가 될 수 있음

 

k-평균 알고리즘 방식

1. 무작위로 k개의 클러스터 중심을 정함

2. 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정

3. 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경

4. 클러스터 중심에 변화가 없을 때까지 2~3 반복

 

k-평균

KMeans 클래스

!wget https://bit.ly/fruits_300_data -O fruits_300.npy
import numpy as np

fruits = np.load('fruits_300.npy')
fruits_2d = fruits.reshape(-1, 100*100)

from sklearn.cluster import KMeans

km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_2d)

KMeans(n_clusters=3, random_state=42)

print(km.labels_)

[2 2 2 2 2 0 2 2 2 2 2 2 2 2 2 2 2 2 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 2 0 2 2 2 2 2 2 2 0 2 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 2 2 2 2 2 2 2 2 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 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 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 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]

print(np.unique(km.labels_, return_counts=True))

(array([0, 1, 2], dtype=int32), array([111, 98, 91]))

import matplotlib.pyplot as plt

def draw_fruits(arr, ratio=1):
    n = len(arr)    # n은 샘플 개수입니다
    # 한 줄에 10개씩 이미지를 그립니다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산합니다. 
    rows = int(np.ceil(n/10))
    # 행이 1개 이면 열 개수는 샘플 개수입니다. 그렇지 않으면 10개입니다.
    cols = n if rows < 2 else 10
    fig, axs = plt.subplots(rows, cols, 
                            figsize=(cols*ratio, rows*ratio), squeeze=False)
    for i in range(rows):
        for j in range(cols):
            if i*10 + j < n:    # n 개까지만 그립니다.
                axs[i, j].imshow(arr[i*10 + j], cmap='gray_r')
            axs[i, j].axis('off')
    plt.show()

draw_fruits(fruits[km.labels_==0])

draw_fruits(fruits[km.labels_==1])

draw_fruits(fruits[km.labels_==2])

클러스터 중심

draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3)

print(km.transform(fruits_2d[100:101]))
print(km.predict(fruits_2d[100:101]))
draw_fruits(fruits[100:101])
print(km.n_iter_)

[[3393.8136117 8837.37750892 5267.70439881]]

[0]

4

최적의 k 찾기

inertia = []
for k in range(2, 7):
    km = KMeans(n_clusters=k, random_state=42)
    km.fit(fruits_2d)
    inertia.append(km.inertia_)

plt.plot(range(2, 7), inertia)
plt.xlabel('k')
plt.ylabel('inertia')
plt.show()

 

728x90

+ Recent posts