1. 군집 알고리즘
<키워드 정리>
비지도 학습
: 훈련 데이터에 타깃이 없어(정답지 없음)
- 스스로 유용한 무언가를 학습해야 해.
- 대표적인 알고리즘 : 군집, 차원 축소
군집(clustering)
: 비슷한 샘플끼리 하나의 그룹으로 모으는 대표적인 비지도 학습 작업
- 군집 알고리즘으로 모은 샘플 그룹을 클러스터(cluster)
🔎 npy파일
넘파이 배열의 기본 저장 포맷 npy
이미지 데이터 각 픽셀을 수치화하여 npy 파일로 만들 수 있어
1. 코랩에서 npy 파일 다운받기
=> wget 리눅스 명령어 사용해야 함.
- 코랩은 파이썬 기반으로 이루어져있기 때문에 그냥 쓸 수 없어 !(느낌표) 붙이기
!wget https://bit.ly/fruits_300_data -O fruits_300.npy
-O옵션 저장할 파일 이름 지정
=> 코랩 콘텐츠 폴더에 저장됨(파일 닫으면
2. 넘파이에서 npy 파일 로드하기
=> 넘파이가 가지고 있는 load() 메서드 사용
import numpy as np
fruits = np.load('fruits_300.npy')
- 동일한 위치에서 실행하면 경로명 없어도 됨.
3. 넘파이 배열로 저장된 이미지 그리기
=> 맷플롯립에 imshow() 함수 사용
import matplotlib.pyplot as plt
plt.imshow(fruits[0], cmap='gray')
plt.show()
+ 그린 이미지 파일로 저장하기
=> PIL패키지의 Image.fromarray()사용하여 numpy배열을 PIL이미지로 변환
=> save()를 통해 저장
import numpy as np
from PIL import Image
im = Image.fromarray(fruits[0])
im.save("filename.jpeg")
2. k-평균
<키워드 정리>
k-평균 알고리즘
: 처음에 랜덤하게 클러스터 중심을 정하고 클러스터를 만든다. 그다음 클러스터의 중심을 이동하고 다시 최적의 클러스터를 구성하는 알고리즘
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
- n_clusters 클러스터의 개수 지정(기본값 8)
- 군집된 결과 labels_ 속성에 저장됨 (배열의 길이=샘플의 개수)
클러스터 중심(센트로이드)
: k-평균 알고리즘이 만든 클러스터에 속한 샘플의 특성 평균값
- 가장 가까운 클러스터 중심을 샘플의 또 다른 특성으로 사용하거나 새로운 샘플에 대한 예측으로 활용할 수 있음
- clusters_centers_ 속성에 저장됨
- n_init 최적의 클러스터를 찾기 위해 알고리즘이 반복한 횟수를 지정(기본값 10)
- 최적의 클러스터를 찾기 위해 알고리즘이 반복한 횟수 n_iter_ 속성에 저장됨
- max_iter 한 번 실행에서 최적의 센트로이드를 찾기 위해 반복할 수 있는 최대 횟수(기본값 200)
엘보우 방법
: 클러스터 개수를 늘려가면서 이너셔의 변화를 관찰하여 최적의 클러스터 개수를 찾는 방법
- 클러스터 개수에 따라 이너셔 감소가 꺽이는 지점이 적절한 클러스터 개수k
이너셔
- 클러스터 중심과 샘플 사이 거리의 제곱합
- 클러스터의 샘플이 얼마나 가깝게 모여있는지를 나타내는 값
- 자동으로 이너셔를 계산해 inertia_ 속성에 저장됨
🔍 k-means 알고리즘으로 군집화하는 5단계
1. 군집의 개수(k) 설정하기
- 몇 개의 군집으로 군집화할지는 사람이 정해야 함
=>군집의 개수 설정을 어떻게 하냐에 따라 결과가 크게 달라짐
=> 군집의 개수 설정을 위한 방법론 존재
① Rule of thumb ② Elbow Method ③ 정보 기준 접근법(Information Criterion Approach)
2. 초기 중심점 설정하기(center of cluster / centeroid = 무게중심)
=> 초기 중심 값 설정을 위한 방법
① Randomly Select ② Manually assign ③ K-means++
3. 데이터를 군집에 할당하기
- 거리 상 가장 가까운 군집(중심점)으로 주어진 모든 데이터를 할당한다.
- 거리 측정 방법은 일반적으로 유클리드 거리(피타고라스)로 측정한다.
(유클리드: / 맨하탄: 빌딩 사이 어떻게 빨리 갈까)
4. 중심점 재설정하기
- 군집의 중심점을 그 군집에 속하는 데이터들의 중간(평균)에 위치한 지점으로 재설정한다.
5. 데이터를 군집에 재할당하기
- 3에서 했던 방법과 똑같이 시행하며 더 이상 중심점의 이동이 없을 때까지 4와 5를 반복한다.
3. 주성분 분석
❓ k-means 알고리즘 한계?
너무 많은 사진이 등록되어 저장공간이 부족해
=> 군집이나 분류에 영향을 끼치지 않으면서 업로드된 사진의 용량를 줄이자
=> 주성분 분석
- 크기가 줄어든만큼 처리속도 빨라짐 처리속도 높이자
- 이미지 한 장 2차원 배열 => 1차원 배열로 바꿔
일반적으로 주성분은 원본 특성의 개수만큼 찾을 수 있다.
(ex. 사과 한 개의 특성 10000개)
- 차원을 줄여서 저장공간을 절약하자
- 차원축소알고리즘
<키워드 정리>
차원 축소
: 원본 데이터의 특성을 적은 수의 새로운 특성으로 변환하는 비지도 학습의 한 종류
- 저장공간을 줄이고 시각화하기 쉬움
- 다른 알고리즘의 성능을 높일 수도 있음
주성분 분석
: 차원 축소 알고리즘의 하나로 데이터에서 가장 분산이 큰 방향을 찾는 방법
- 원본 데이터를 주성분에 투영하여 새로운 특성을 만들 수 있음
- 일반적으로 주성분은 원본 데이터에 있는 특성 개수보다 작음
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
* 객체 만들 때 주성분 지정해야 함
n_components= 개수 or 0~1 사이의 비율
- PCA 클래스가 찾은 주성분 components_ 속성에 저장됨
- transform() 메서드를 사용해 차원을 줄일 수 있음
- inverse_transform() 메서드를 사용해 차원을 복원할 수 있음(100%x 손실 발생)
설명된 분산
: 주성분 분석에서 주성분이 얼마나 원본 데이터의 분산을 잘 나타내는지 기록한 것
- explained_variance_ratio_에 설명된 분산 비율이 기록됨
- 첫 번째 데이터가 가장 분산이 큼
- 분산 비율을 모두 더하면 총 분산 비율을 얻을 수 있음
⚡경고 메시지⚠
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT
=> 스케일링 부족해서 최대학습을 진행하지 못했다
< 코드정리>
6-1.
# 300개의 사진을 넘파이 배열로 바꿔서 저장시켜놓은 npy 파일
!wget https://bit.ly/fruits_300_data -O fruits_300.npy
# npy 파일 로드하기
# 시각화 이미지로 복원할 거야
import numpy as np
import matplotlib.pyplot as plt
fruits = np.load('fruits_300.npy') # 동일한 위치에서 실행하면 경로명 없어도 돼
# 타입 확인
type(fruits) >>> numpy.ndarray # 넘파이의 배열로
print(fruits.shape) >>> (300, 100, 100) # 3차원 배열 (샘플의 개수, 높이, 너비) => 배열의 크기 100*100
# 첫 번째 이미지의 첫 번째 행 출력
print(fruits[0, 0, :]) >>> [ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1
2 2 2 2 2 2 1 1 1 1 1 1 1 1 2 3 2 1
2 1 1 1 1 2 1 3 2 1 3 1 4 1 2 5 5 5
19 148 192 117 28 1 1 2 1 4 1 1 3 1 1 1 1 1
2 2 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검정색 255하얀색
# 넘파이 배열로 저장된 이미지 그리기
plt.imshow(fruits[0], cmap='gray')
plt.show()
#반전 시키기 (데이터는 그대로야)
plt.imshow(fruits[0], cmap='gray_r')
plt.show()
# 그린 이미지 파일로 저장
import numpy as np
from PIL import Image
im = Image.fromarray(fruits[0]) #이미지 클래스 안에 fromarray함수 사용해 변수에 저장
im.save("filename.jpeg") #save 함수 사용해 로컬에 저장
# 하나의 차트에 여러 이미지 출력
fig, axs = plt.subplots(1,2) # 몇 행 몇 열로 쪼개겠다
axs[0].imshow(fruits[100], cmap='gray_r')
axs[1].imshow(fruits[200], cmap='gray_r')
plt.show()
# 0~99 사과 #100~199 파인애플 #200~ 바나나라고 유추,,,
# 픽셀값 분석하기
# 데이터 연산 속도 때문에 1차원으로 바꿔주기
apple = fruits[0:100].reshape(-1, 100*100)
pineapple = fruits[100:200].reshape(-1, 100*100)
banana = fruits[200:300].reshape(-1, 100*100)
print(apple.shape) >>> (100, 10000)
# 총 100개의 데이터 / 각각 10000개씩 있어
# axis =1 방향으로 각 데이터에 대한 평균을 구해 # 100개에 대한 각각 평균
print(apple.mean(axis=1)) >>> [ 88.3346 97.9249 87.3709 98.3703 92.8705 82.6439 94.4244 95.5999
90.681 81.6226 87.0578 95.0745 93.8416 87.017 97.5078 87.2019
88.9827 100.9158 92.7823 100.9184 104.9854 88.674 99.5643 97.2495
94.1179 92.1935 95.1671 93.3322 102.8967 94.6695 90.5285 89.0744
97.7641 97.2938 100.7564 90.5236 100.2542 85.8452 96.4615 97.1492
90.711 102.3193 87.1629 89.8751 86.7327 86.3991 95.2865 89.1709
96.8163 91.6604 96.1065 99.6829 94.9718 87.4812 89.2596 89.5268
93.799 97.3983 87.151 97.825 103.22 94.4239 83.6657 83.5159
102.8453 87.0379 91.2742 100.4848 93.8388 90.8568 97.4616 97.5022
82.446 87.1789 96.9206 90.3135 90.565 97.6538 98.0919 93.6252
87.3867 84.7073 89.1135 86.7646 88.7301 86.643 96.7323 97.2604
81.9424 87.1687 97.2066 83.4712 95.9781 91.8096 98.4086 100.7823
101.556 100.7027 91.6098 88.8976]
# 히스토그램 그리기
plt.hist(np.mean(apple, axis=1), alpha=0.8) # 겹쳐도 어느정도 보여주기 위해 투명도 조절
plt.hist(np.mean(pineapple, axis=1), alpha=0.8)
plt.hist(np.mean(banana, axis=1), alpha=0.8)
plt.legend(['apple', 'pineapple', 'banana'])
plt.show()
# 다시 axis =0 방향으로 각 픽셀별 평균을 구해
fig, axs = plt.subplots(1, 3, figsize=(20,5))
axs[0].bar(range(10000), np.mean(apple, axis=0)) #bar차트 반드시 x축 y축 값 있어야해
axs[1].bar(range(10000), np.mean(pineapple, axis=0))
axs[2].bar(range(10000), np.mean(banana, axis=0))
plt.show()
apple_mean = np.mean(apple, axis=0).reshape(100, 100)
pineapple_mean = np.mean(pineapple, axis=0).reshape(100,100)
banana_mean = np.mean(banana, axis=0).reshape(100, 100)
fig, axs = plt.subplots(1, 3, figsize=(20,5))
axs[0].imshow(apple_mean, cmap='gray_r')
axs[1].imshow(pineapple_mean, cmap='gray_r')
axs[2].imshow(banana_mean, cmap='gray_r')
plt.show()
# 평균낸 이미지 합쳐서 뭉게진 것처럼 보여
# 평균값과 가까운 사진 고르기
# 절댓값 오차 사용
abs_diff = np.abs(fruits - apple_mean)
abs_mean = np.mean(abs_diff, axis=(1,2)) # 시각화 위해 차원으로 만들어줘 # 3차원
# abs_mean = np.mean(abs_diff) 는 1차원이야
print(abs_mean.shape)
# 가장 작은 순서대로 100개 골라
# 넘파이 정렬 함수 #기본값 오름차순
apple_index = np.argsort(abs_mean)[:100] # 정렬된 인덱스 번호만 반환(실제값x)
fig, axs = plt.subplots(10, 10, figsize=(10,10))
for i in range(10):
for j in range (10):
axs[i, j].imshow(fruits[apple_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off') #축을 꺼줘
plt.show()
pineapple_index = np.argsort(abs_mean)[100:200] # 정렬된 인덱스 번호만 반환(실제값x)
fig, axs = plt.subplots(10, 10, figsize=(10,10))
for i in range(10):
for j in range (10):
axs[i, j].imshow(fruits[pineapple_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off') #축을 꺼줘
plt.show()
banana_index = np.argsort(abs_mean)[200:] # 정렬된 인덱스 번호만 반환(실제값x)
fig, axs = plt.subplots(10, 10, figsize=(10,10))
for i in range(10):
for j in range (10):
axs[i, j].imshow(fruits[banana_index[i*10 + j]], cmap='gray_r')
axs[i, j].axis('off') #축을 꺼줘
plt.show()
6-2.
# 6-2.k-means
!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) # 2차원 배열로 변경
# 변수 확인 반드시 하기
print(fruits_2d.shape) >>> (300, 10000)
# k-means 클래스
# 비지도 학습 타깃 데이터 없음
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42) #중심점 3개로 잡았어
km.fit(fruits_2d) # 모델 만들었으면 fit
# labels_배열의 값 0,1,2 세 개 중 하나가 들어갔어 #실제로 모이는 건 x
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]
# 레이블의 순서는 의미 없음
#pc 성능 마다 그 때 그 때 어느걸 먼저 계산하느냐
# 센터 포인트 랜덤하게 잡혀서
# 유니크한 값 몇 개씩 있는지 카운트
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) # 배열의 길이 알아내
# 한 줄에 10개씩 이미지 그리기 (샘플 개수 10으로 나누어 전체 행 개수 계산)
rows = int(np.ceil(n/10)) # ceil 올림 나눗셈 들어가면 뒤에 .이 붙어
# 행이 1개이면 열의 개수는 샘플개수
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:
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])
# 클러스터 중심
print(km.cluster_centers_) >>> [[1. 1. 1. ... 1. 1. 1. ]
[1.10204082 1.07142857 1.10204082 ... 1. 1. 1. ]
[1.01098901 1.01098901 1.01098901 ... 1. 1. 1. ]]
print(km.cluster_centers_.shape) >>> (3, 10000)
# 센터포인트 세 개 만들어놨어
draw_fruits(km.cluster_centers_.reshape(-1,100, 100), ratio=3)
# kk-means 자동으로 거리를 확인해주는 transform 메서드
# 특성값을 변환하는 도구로도 사용할 수 있어 (StandardClas처럼)
print(km.transform(fruits_2d[100:101])) >>> [[3393.8136117 8837.37750892 5267.70439881]]
# predict으로 확인
print(km.predict(fruits_2d[100:101])) >>> [0]
draw_fruits(fruits[100:101])
# 최적의 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()
# 엘보우 찾아 센터가 3개일때
# 더 많아지면 별 다른 변화가 없을 거야
6-3. 주성분 분석
!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 클래스가 찾은 주성분 속성
print(pca.components_.shape) >>> (50, 10000)
########### 과일그리는 함수 #############
import matplotlib.pyplot as plt
def draw_fruits(arr, ratio=1):
n = len(arr) # 배열의 길이 알아내
# 한 줄에 10개씩 이미지 그리기 (샘플 개수 10으로 나누어 전체 행 개수 계산)
rows = int(np.ceil(n/10)) # ceil 올림 나눗셈 들어가면 뒤에 .이 붙어
# 행이 1개이면 열의 개수는 샘플개수
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:
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))
# 원본 데이터 축소
# 특성에 맞춰서 투영시킬 거야
print(fruits_2d.shape) >>> (300, 10000)
fruits_pca = pca.transform(fruits_2d) # 투영시켜
print(fruits_pca.shape) >>> (300, 50)
# 축소 데이터 특성 주요성분 50개
# 원본 데이터 재구성
# 주요성분을 가지고 다시 복원시킬 때 90%이상이지만 어느 정도 손실이 있음(뭉게져)
fruits_inverse = pca.inverse_transform(fruits_pca) # 역으로 복원
print(fruits_inverse.shape) >>> (300, 10000)
fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100)
for start in [0, 100, 200]:
draw_fruits(fruits_reconstruct[start:start+100])
print("/n")
# 설명된 분산
print(pca.explained_variance_ratio_) >>> [0.42357017 0.09941755 0.06577863 0.04031172 0.03416875 0.03281329
0.02573267 0.02054963 0.01372276 0.01342773 0.01152146 0.00944596
0.00878232 0.00846697 0.00693049 0.00645188 0.00578895 0.00511202
0.0048638 0.00480344 0.00447837 0.00437314 0.00408041 0.00389479
0.00372431 0.00359213 0.00331452 0.00317816 0.0030432 0.0030368
0.00288899 0.00275878 0.00264793 0.00255721 0.00252146 0.00246913
0.00239401 0.00230534 0.00220818 0.00215509 0.00213161 0.00196391
0.00193053 0.00190962 0.00184563 0.00182855 0.00170514 0.00167385
0.00163105 0.00159452]
print(np.sum(pca.explained_variance_ratio_)) >>> 0.9214965776590037
#합해봤더니 92%넘는 분산값 유지
plt.plot(pca.explained_variance_ratio_)
plt.show()
############### 다른 알고리즘과 함께 사용하기 ############
######## 로지스틱
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
# 로지스틱 지도학습 정답지 있어야 해
target = np.array([0]*100 + [1]*100 + [2]*100)
# 우리 데이터 100개씩 사과/파인애플/바나나 나눠져있어서 가능..
# 교차검증 수행
from sklearn.model_selection import cross_validate
scores = cross_validate(lr, fruits_2d, target) #교차 검증 (어느 모델을 할 거야, 원본 데이터, 정답지)
print(np.mean(scores['test_score'])) >>> 0.9966666666666667
print(np.mean(scores['fit_time'])) >>> 1.3755132675170898
# 주성분에 투영시킨 데이터 # 축소데이터 가지고 교차검증
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score'])) >>> 1.0
print(np.mean(scores['fit_time'])) >>> 0.024224376678466795
# 시간 많이 단축되었어 #fit_time은 코랩속도 컴퓨터마다 달라
# n_components 매개변수 설정
# 정수로 넣으면 개수 # 0~1 사이의 실수로 넣으면 비율
pca = PCA(n_components=0.5)
pca.fit(fruits_2d)
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']))
# 경고 메시지 달라
# 1. 반복횟수 2. 스케일링 부족해서 최대학습을 진행하지 못했다
############## k-means
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_pca)
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()
'MLOps 개발자 양성과정 > ml&dl' 카테고리의 다른 글
[Day-56] chap08. 이미지를 위한 인공신경망 (0) | 2023.03.15 |
---|---|
[Day-55] chap07.딥러닝_인공신경망 (0) | 2023.03.13 |
[Day-53] chap.05_트리 알고리즘 (0) | 2023.03.10 |
[Day-52] 로지스틱 회귀 / 확률적 경사 하강법 (0) | 2023.03.08 |
[Day-51] 머신러닝_ 회귀 (0) | 2023.03.07 |