1. 인공지능
- 지능 : 문제를 해결할 수 있는 능력
- 환자를 보고 병을 진단
- 인공지능: 지능 작업을 수행할 수 있는 기계의 능력
- 환자에 대한 정보를 입력하면 컴퓨터가 병을 진단
- 구현 방법: 지식 공학(전문가 시스템): 문제 해결을 위한 알고리즘을 사람이 작성
- 전문가의 도움을 받아서 개발자가 알고리즘을 작성해서 컴퓨터에 저장하고 이 알고리즘을 따라서 문제 해결
- 컴퓨터의 역할은 결과를 만들어내는 것
- Machine Learning
- Data와 Output을 주면 컴퓨터가 알고리즘을 만들어내는 방식
인공지능과 머신러닝의 관계
- 인공지능 > 기계학습(머신러닝) > 딥러닝, 강화학습
- 전문가 시스템 -> 머신 러닝 -> 딥러닝, 강화학습
- 딥러닝은 이겼다, 졌다로 판정해주지만 강화학습은 순간순간 확률을 보여준다.=> 게임에 적합
- 이미지 데이터가 존재하는 경우 머신 러닝은 이미지 데이터 1개를 데이터 1개로 바라보지만 딥러닝은 이를 작게 쪼개서 그 안에서 알고리즘을 찾을 수 있음
2. Machine Learning
- 데이터를 가지고 학습하도록 컴퓨터를 프로그래밍하는 과학
- 명시적으로 프로그램 되는 것이 아니라 훈련되며 작업과 관련있는 샘플을 제공하면 이 데이터에서 통계적 구조를 찾아 그 작업을 자동화하기 위한 규칙을 만들어내는 것
- 필요 요소
- 입력 데이터 포인트: 최근에는 여러 입력 데이터 포인트로 얻어진 데이터를 한 곳에 모아서 처리하는 부분에 대해 중점
- 데이터 발생지가 여러 곳인 경우 별도로 처리하는 것이 어렵기 때문에 한 곳에 잘 정리를 해서 모으는 것이 중요
- 기대 출력: 어떤 결과를 원하는지
- 알고리즘 성능 측정 방법: 평가 지표
1) 사용하는 이유
- 전통적인 방식으로는 너무 복잡하거나 알려진 알고리즘이 없는 문제
- 음성인식은 직접 알고리즘을 만들기에는 너무 복잡해서 머신러닝을 이용
- 머신 러닝을 통해 학습을 할 수 있기 때문
대용량의 데이터를 분석하다보면 기존에 알고 있지 않은 또는 겉으로는 보이지 않는 패턴 발견 가능 - 데이터 마이닝
2) 역사
- 확률적 모델링
- 나이브 베이즈
- 로지스틱 회귀
- 신경망
- 등장은 1950년대, 이때는 컴퓨터 성능이 좋지 못해서 효과적인 훈련 방법을 찾지 못했다.
- 1989년 얀 르쿤에 의해 초창기 합성곱 신경망이 등장하면서 다시 각광
- 커널 방법
- 분류에 사용되었는데 선형이 아닌 비선형으로 결정 경계 만들기 시작
- Decision Tree, Random Forest, Gradient Boosting: 앙상블 모형
- 컴퓨터 성능이 좋아지면서 하나의 알고리즘을 부트스트랩을 이용하거나 여러 개의 알고리즘을 한꺼번에 학습하는 방법
- 신경망
- 생성형 AI
3) 분류
- 레이블(정답)의 존재 여부에 따른 분류
- 지도학습: 레이블 존재 (회귀 or 분류)
- 비지도학습: 레이블 없음 (주성분분석, 군집, 연관분석 등)
- 준지도학습: 레이블을 만드는 작업 (레이블이 일부분밖에 없어서)
- 강화학습: 보상이 주어지는 방식
- 실시간 점진적으로 학습을 할 수 있는지 여부
- 온라인학습: 점진적 학습 가능
- 실시간으로 데이터가 들어오는 경우도 학습이 가능하다.
- 배치학습: 점진적 학습 불가능
- 데이터가 확정이 되어있어야 한다.
- 사례 기반 학습과 모델 기반 학습
- 사례 기반 학습: 알고 있는 데이터와 새 데이터를 비교하는게 목적
- 모델 기반 학습: 패턴을 발견해서 예측 모델을 만드는 방식
4) 지도학습 (Supervised Learning)
- 레이블이 존재하는 학습
- 입력-출력 쌍들을 매핑해주는 함수 학습
- 종류
- 출력이 이산적일 때: 분류
- 출력이 연속적일 때: 회귀
- 출력이 확률인 경우: 추정 (Deep Learning)
- 단점
- 사용할 수 있는 데이터에 한계
- 데이터를 생성하는 데 많은 비용
- 선형회귀
- 로지스틱 회귀
- k-최근접 이웃
- 서포트 벡터 머신
- 결정 트리
- 랜덤 포레스트
- 신경망
- 로지스틱 회귀를 제외하고는 분류와 회귀에 모두 사용 가능
- 로지스틱 회귀는 분류만 가능
5) 비지도 학습(Unsupervised Learning)
- 레이블이 존재하지 않는 학습
- 데이터에 내재된 고유의 특징을 탐색하기 위해서 사용
- 지도 학습에 비해서 학습하기 어려움
- 군집
- k means
- DBSCAN
- 계층군집
- 이상치 탐지와 특이치 탐지
- 원클래스
- 아이솔레이션 포레스트
- 시각화와 차원 축소
- PCA (주성분 분석)
- LLE (지역적 선형 임베딩)
- t-SNE
- 연관 규칙 학습
- Apriori
- eclat
6) 준지도 학습
- 라벨링이 일부분만 되어있어서 그 데이터를 이용해서 라벨이 없는 데이터에 라벨을 붙이기 위해서 사용
7) 강화 학습
- 결과가 바로 주어지지 않고 시간이 지나서 주어지는 방식
- 최근에 로봇 같은 분야에서 많이 이용
8) 애플리케이션 사례
- Netflix의 영화 추천 시스템: 고객의 평점작성 내역과 구매 내역을 이용해서 추천
- 미국 국가 안보국의 SKYNET: 파키스탄의 테러리스트를 식별해서 사살하기 위한 프로그램
- 휴대 전화 기록을 이용하여 휴대 전화를 자주 끄거나 USIM을 변경하는 사람을 테러리스트로 식별해서 사살했는데 잘못된 알고리즘으로 무고한 사람이 희생됨
3. scikit learn
- 파이썬 머신러닝 패키지 중 가장 많이 사용되는 라이브러리
- 가장 Python스러운 API
- 패키지: sklearn
- 아나콘다는 내장
4. 데이터 표현 방식
1) 테이블로서의 데이터
- 기본 테이블은 2차원 데이터 그리드 형태
- 행: 데이터 세트의 개별 요소, sample이라 부르고 행의 개수는 n_sample이라 표현
- 열:각 요소와 관련된 수량, feature 또는 target이라고 부르는 경우가 많고 열의 개수를 n_features라고 표현
- feature: 독립적인 데이터
- Target : feature로 인해서 만들어지는 데이터로 label이라고도 함
2) feature
- 보통은 X라는 변수에 저장
- 특징 행렬이라는 표현을 사용. [n_sampels, n_features]의 모양을 가진 2차원 행렬이라 가정하며 실제 자료형은 numpy의 ndarray나 pandas의 DataFrame으로 되어 있는 경우가 많은데 가끔 sklearn의 희소 행렬인 경우도 있음
- 정량적인 데이터여야 하기 때문에 대부분의 경우는 실수지만 이산적인 데이터아 부울도 가ㅡㄴㅇ
3) target
- 대상 행렬이라고 하는데 y로 표시
- numpy의 1차원 ndarray나 pandas의 Series인 경우가 많음
- 연속적인 수치가 이산 클래스를 가질 수 있음
import seaborn as sns
iris = sns.load_dataset('iris')
#특징 행렬과 타겟 분리
X_iris = iris.drop('species', axis=1)
Y_iris = iris['species']
#species를 분류하기 위한 데이터 (타겟) #나머지 데이터는 특징행렬 |
5. Estimator API(머신러닝 모델 API)
1) 기본 원칙
- 일관성
- 모든 객체는 일관된 문서를 갖춘 제한된 함수 집합에서 비롯된 공통 인터페이스 공유
- 거의 모든 객체는 동일한 작업을 수행하는 메소드를 공통으로 소유
- 템플릿 메소드 패턴: 공통으로 사용될 것 같은 메소드를 인터페이스에 등록하고 이를 클래스에서 구현해서 사용
- 검사 (inspection)
- parameter: 함수나 기능을 수행하기 위해서 내부적으로 사용하는 데이터. argument, 인수, 인자, 매개변수라고 하기도 함
- hyper parameter: 개발자가 직접 설정하는 파라미터.
- hyper parameter 튜닝은 값을 변경해서 더 좋은 모델을 만들거나 최적의 값을 찾아가는 작업이다.
- 모든 hyper parameter를 public 속성으로 노출해서 확인이 가능하도록 함
- 제한된 객체 계층 구조
- 알고리즘만 python 클래스에 의해 표현, 데이터세트는 표준 포맷으로 표현, 매개변수 이름은 문자열
- 표준 포맷(numpy의 ndarray, pandas의 DataFrame, scipy의 Sparse Matrix)
- 구성
- 대부분의 머신러닝 작업은 기본 알고리즘의 시퀀스로 나타낼 수 있음 (순서대로)
- 합리적인 기본값
- 대다수의 하이퍼 파라미터는 라이브러리가 적절한 기본값을 가지도록 정의
2) 사용 방법
- 적절한 모델 클래스 mport
- 모델 클래스를 인스턴스화 할 때 적절한 하이퍼 파라미터를 설정
- 데이터를 특징 배열과 타겟 배열로 생성
- 모델 클래스의 인스턴스의 fit 메소드를 호출해서 모델을 데이터에 적합하도록 훈련
- 모델을 새 데이터에 적용
- 지도 학습의 경우: predict 함수에 새로운 데이터 사용해서 예측
- 비지도 학습의 경우: transform이나 predict를 이용해서 데이터의 속성을 변환하거나 예측
3) 선형 회귀 수행
- sklearn.linear_model.LinearRegression
#샘플 데이터 생성
rng = np.random.RandomState(42)
#데이터 50개 생성
x = 10 * rng.rand(50)
#데이터를 이용해서 타겟 데이터 생성 - rng.randn(50)은 잡음
y = 2 * x -1 + rng.randn(50)
#x 데이터를 특징 행렬로 변환
print(x.shape) #1차원 배열 - 특성 배열은 2차원 배열, DataFrame, 희소 행렬
X = x.reshape(x.shape[0], -1) #x[:, np.newaxis]도 가능
print(X.shape) # X는 특성 배열이 되었다.
(50,) (50, 1) |
#추정기 인스턴스 생성
from sklearn.linear_model import LinearRegression
model = LinearRegression(fit_intercept=True)
#기존 데이터로 훈련
model.fit(X, y)
#훈련 결과 확인
print("회귀 계수:", model.coef_)
print("절편:", model.intercept_)
회귀 계수: [1.9776566] 절편: -0.9033107255311164 |
- 훈련 결과를 확인 - 스스로 만든 파라미터나 결과에는 _가 붙음
- 하이퍼 파라미터에는 _가 붙지 않음
#회귀는 지도학습: predict 함수로 예측
xfit = np.linspace(-1, 11)
Xfit = xfit[:, np.newaxis]
yfit = model.predict(Xfit)
#시각화
plt.scatter(x, y)
plt.plot(xfit, yfit)
- 잡음을 섞어서 일정하게 나오지는 않는다.
4) 평가 지표를 이용한 성능 평가
- 앞의 방식은 모든 데이터를 가지고 훈련을 해서 모델을 만든 후 새로운 데이터에 적용한 방법
- 여러 모델을 이용해서 만든 모델을 평가할 수 없다.
- 일반적으로 머신러닝에서는 기존 데이터를 분할해서 훈련에 사용하고 나머지 데이터를 이용해서 모델을 평가한다.
- 여러 머신러닝 추정기를 적용하고 최적의 성능을 가진 모델을 선택하는 것이 일반적
6. Machine Learning 절차
1) 순서
- 작업 환경 설정: 파이썬 설치, 가상 환경 생성, 필요한 패키지 설치
- 서비스를 만들고자 하는 경우는 가상 환경 생성 작업이 필수
- 문제 정의
- 데이터 수집
- 데이터 탐색
- 데이터 전처리
- 모델을 선택하고 훈련
- 평가하고 전처리부터 다시 수행
- 최적의 모델을 선택하고 솔루션 제시
- 시스템을 런칭하고 모니터링 하면서 유지보수
2) 실행
- 환경 설정
- 데이터 수집 : housing.csv
- 캘리포니아 주택 데이터셋
- 블록 별로 여러 컬럼들을 소유하고 있음
- 문제 정의: 중간 주택 가격 예측
- 주택 가격이 이미 존재하므로 지도학습이다.
- 주책 가격은 연속형 데이터이므로 회귀 분석
- 데이터를 불러와서 탐색
# 데이터 탐색
housing = pd.read_csv('./python_machine_learning-main/data/housing.csv')
housing
#각 열읱 특성 파악
housing.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 20640 entries, 0 to 20639 Data columns (total 10 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 longitude 20640 non-null float64 1 latitude 20640 non-null float64 2 housing_median_age 20640 non-null float64 3 total_rooms 20640 non-null float64 4 total_bedrooms 20433 non-null float64 5 population 20640 non-null float64 6 households 20640 non-null float64 7 median_income 20640 non-null float64 8 median_house_value 20640 non-null float64 9 ocean_proximity 20640 non-null object dtypes: float64(9), object(1) memory usage: 1.6+ MB |
- total_berooms는 결측치 존재
- ocean_proximity는 자료형이 객체 - 문자열
#문자열 컬럼은 범주형인지 확인
housing['ocean_proximity'].value_counts()
ocean_proximity <1H OCEAN 9136 INLAND 6551 NEAR OCEAN 2658 NEAR BAY 2290 ISLAND 5 Name: count, dtype: int64 |
- 5개 종류인 것으로 봐서 범주형이다.
#숫자데이터 범위 확인
housing.describe()
#숫자 데이터는 분포 확인 - 히스토그램
housing.hist(bins=50, figsize=(20, 15))
plt.show()
- 데이터의 분포가 한쪽으로 몰린 경우에는 데이터의 분포가 조금 더 중앙에 많이 몰리도록 수정할 필요가 있다. (로그변환)
- 좌우로 너무 넓게 펼쳐져있으면 극단치를 제거하는 것에 대해서 고려
- 각 숫자 데이터의 범위를 비교해서 범위가 차이가 많이 나면 스케일링 고려
- population이 너무 크다.
- total_rooms의 max가 이상하다.
- 데이터 분리
- 훈련 데이터와 테스트 데이터 또는 검증용 데이터로 분리하는 것이 일반적
- 데이터 전체를 파악하기 전에 분리하는 것이 좋다.
- 전체 데이터를 가지고 데이터 탐색을 수행하게 되면 과대적합 가능성이 발생한다.
- 사람의 뇌가 패턴을 감지해버리기 때문이다.
- 이러한 현상을 Data Snooping이라고 함
- 데이터를 나눌 때 보통 7:3, 8:2를 많이 이용하지만 데이터 개수에 따라 다른 선택을 할 수 있다. 일반적으로 데이터가 많으면 훈련 데이터의 비율을 낮추고 데이터의 개수가 적으면 훈련 데이터의 비율을 높인다.
- 데이터가 아주 많으면 검증용 데이터를 별도로 분할해도 된다.
- 시계열 데이터는 데이터를 순차적으로 분할한다.
- 훈련을 여러번 반복해서 수행하면 알고리즘의 비교 측면이나 모든 데이터를 샘플로 사용하게 되는 상황을 방지하기 위해서 일정한 데이터를 랜덤하게 추출하는 경우도 있다.
- 분류 문제에서는 타겟의 비율이 다르다면 층화 추출도 고려
- 100일 중 1번만 비가 온다면, 안온다고 할 떄 정확도가 99%가 된다.
비가 오는 경우와 안오는 경우를 적절히 섞어야 한다.
- 100일 중 1번만 비가 온다면, 안온다고 할 떄 정확도가 99%가 된다.
# sklearn 의 model_selection.train_test_split API를 이용한 데이터 분리
import sklearn
help(sklearn.model_selection.train_test_split)
- arrys는 데이터 배열
- test_size는 테스트 데이터 비율
- train_size는 훈련 데이터의 비율로 test_size를 설정하면 설정하지 않음
- 데이터가 아주 많으면 훈련하는 데 시간이 너무 많이 걸릴 수 있어서 설정하기도 함
- random_state는 시드 번호로 설정하는 것을 권장
- shuffle은 데이터를 섞을지 여부로 random_state를 설정하면 무의미
- stratify는 측화추출을 하고자 할 때 데이터의 비율
- 리턴되는 데이터는 훈련데이터와 테스트데이터의 튜플
#8:2로 분할 - 데이터를 하나의 데이터로 제공하면 2개로 리턴하고
#특성 배열과 타겟 배열 2개를 대입하면 4개로 리턴
train_set, test_set = sklearn.model_selection.train_test_split(housing,
test_size=0.2,
random_state=42)
#분할된 데이터의 차원 확인
print(train_set.shape)
print(test_set.shape)
(16512, 10) (4128, 10) |
X = housing.drop('median_house_value', axis=1)
y = housing['median_house_value']
result = sklearn.model_selection.train_test_split(X, y, test_size=0.2, random_state=42)
print(type(result))
<class 'list'> |
- 층화 추출: 계층적 샘플링 (데이터를 일정한 비율로 샘플링)
- 회귀나 분류를 할 때 타겟의 데이터 분포가 일정하지 않은 경우 왜곡된 결과를 만들 수 있음
- 분류의 경우 1과 0의 비율을 10대 1 정도 되는 상황에서 훈련 데이터에 0으로 분류되는 데이터가 하나도 없다면 이 경우 모델은 테스트 데이터에 결과가 좋지 않을 것
- 0으로 분류되는 모든 데이터가 훈련 데이터에 포함되어 버리면 잘못하면 테스트 데이터에 완전하게 맞는 결과가 나와버릴 수 있다.
- 회귀의 경우 타겟이 연속형이라면 범주형으로 변환해서 수행해야 한다.
- 이때 사용할 수 있는 함수는 pandas의 cut 함수
- 데이터와 구간의 리스트, 레이블의 리스트 대입
- API 함수는 StratifiedShuffleSplit
- 이 함수의 리턴되는 데이터는 데이터가 아니고 데이터의 인덱스
- 결과를 가지고 다시 데이터 추출을 해야 함
X = housing.drop('median_house_value', axis=1)
y = housing['median_house_value']
X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(X, y, test_size=0.2, random_state=42)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
(16512, 9) (4128, 9) (16512,) (4128,) |
- median_income의 비율을 이용한 층화 추출 (계층적 샘플링)
# 연속형 데이터를 범주형으로 변환
#pd.cut(데이터, bins =[경계값 나열] ,labels =[ 레이블 나열 ])
housing['income_cat'] = pd.cut(housing['median_income'],
bins=[0, 1.5 ,3.0 ,4.5, 6, np.inf],
labels=[1,2,3,4,5])
housing['income_cat'].value_counts()
income_cat 3 7236 2 6581 4 3639 5 2362 1 822 Name: count, dtype: int64 |
# 층화 추출을 위한 객체 생성
#층화 추출을 위한 객체 생성
#n_splits은 조각의 개수
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
result = split.split(housing, housing['income_cat'])
for train_index, test_index in result:
start_train_set = housing.loc[train_index]
start_test_set = housing.loc[test_index]
#비율확인
start_train_set['income_cat'].value_counts() / len(start_train_set)
- k-ford validation: 데이터를 몇조각으로 등분해서, 5조각을 만들고 4개로 모델 만들고 1개로 테스트하고.
- 인덱스를 리턴해주어서 행단위 추출을 다시 해줘야 한다. (for문)
income_cat 3 0.350594 2 0.318859 4 0.176296 5 0.114462 1 0.039789 Name: count, dtype: float64 |
- 데이터 탐색을 완료하기 전에 데이터를 분리하는 것을 권장
- 데이터 탐색: 상관계수 출력
- 데이터의 독립성을 살펴볼 때는 상관계수만 보면 안된다.
여러개의 피쳐가 다른 피쳐를 설명할 수 있기 때문이다. - corr() 함수는 숫자가 아닌 컬럼을 제거하고 사용해야 한다.
#숫자 이외의 컬럼 제거 - housing.info()
corr_matrix = housing.drop("ocean_proximity", axis=1).corr()
corr_matrix
- 방 개수와 침대방 개수는 상관계수가 높다. 당연히 높겠지
# pandas로 해보기
from pandas.plotting import scatter_matrix
scatter_matrix(housing[['median_house_value', 'median_income', 'total_rooms']], figsize=(12, 8))
plt.show()
#출력된 이미지 저장
plt.savefig('산포도', format='png', dpi=300)
- 특성 조합을 이용한 탐색
- 여러 특성을 조합해서 새로운 특성을 만들고, 그 특성과 다른 특성간의 관계 확인하는 것도 중요
- 방의 개수보다 방의 개수 대비 침실의 개수와 같은 특성을 만들어서 확인해볼 수 있다.
housing['bedrooms_per_room'] = housing['total_bedrooms']/housing['total_rooms']
corr_matrix = housing.drop('ocean_proximity', axis=1).corr()
corr_matrix['median_house_value'].sort_values(ascending=False)
median_house_value 1.000000 median_income 0.688075 income_cat 0.643892 total_rooms 0.134153 housing_median_age 0.105623 households 0.065843 total_bedrooms 0.049686 population -0.024650 longitude -0.045967 latitude -0.144160 bedrooms_per_room -0.255880 Name: median_house_value, dtype: float64 |
- median_house_value 를 타겟으로 회귀하려 한다.
- 방의 개수와 침실의 개수는 상관계수가 낮다. 그런데 bedrooms_per_room은 -0.25니까 회귀를 하려면 차라리 이걸 쓰는게 낫다.
- 그래서 도메인 지식이 중요하다.
- 피처와 타겟 분리
#훈련 데이터 복제 - 레이블을 제외한 데이터 복제
housing_feature = start_train_set.drop('median_house_value', axis=1)
#훈련 세트를 위해 레이블 삭제
#레이블에 변형을 적용하지 않기 위해서 레이블값도 복제
housing_leabels = start_train_set['median_house_value'].copy()
- 전처리 - 누락된 데이터 처리
#결측치 확인
#NaN 결측치 확인
sample_incomplete_rows = housing[housing.isnull().any(axis=1)].head()
sample_incomplete_rows
#누락 행 제거
#total_bedrooms가 누락된 행 제거
housing_feature.dropna(subset=["total_bedrooms"]).info()
# Column Non-Null Count Dtype --- ------ -------------- ----- 0 longitude 16354 non-null float64 1 latitude 16354 non-null float64 2 housing_median_age 16354 non-null float64 3 total_rooms 16354 non-null float64 4 total_bedrooms 16354 non-null float64 5 population 16354 non-null float64 6 households 16354 non-null float64 7 median_income 16354 non-null float64 8 ocean_proximity 16354 non-null object 9 income_cat 16354 non-null category |
- 모두 16354!
# 누락 열 제거
#열 제거
sample_incomplete_rows.drop('total_bedrooms', axis=1)
# 누락 값 중간값으로 대체
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy="median")
#숫자로된 컬럼만 추출해서 NaN->중간값 대체
housing_num = housing.select_dtypes(include=[np.number])
imputer.fit(housing_num)
X = imputer.transform(housing_num)
housing_tr = pd.DataFrame(X, columns=housing_num.columns,
index = list(housing.index.values))
housing_tr.head()
- 범주형 데이터 처리
- 머신러닝은 숫자만 다룸
- 범주형이나 문자열 데이터가 있다면 숫자로 변환해야 함
- 범주형의 경우 일련번호 형태로 변경하거나 원핫인코딩 필요
#범주형 데이터 추출
housing_cat = housing_features['ocean_proximity']
#일련번호로 만들기
housing_cat_encoded, housing_categoris = housing_cat.factorize()
print(housing_cat_encoded[:10])
print(housing_categoris)
[0 1 0 1 2 3 2 2 2 2] Index(['INLAND', 'NEAR OCEAN', '<1H OCEAN', 'NEAR BAY', 'ISLAND'], dtype='object') |
- 원핫 인코딩 - 범주형의 개수만큼 열을 만들어서 해당하는 열에만 1 표시
#sklearn 의 변환기들은 2차원 배열을 요구합니다.
from sklearn.preprocessing import OrdinalEncoder
oridinalEncoder = OrdinalEncoder()
result = oridinalEncoder.fit_transform(housing_features['ocean_proximity'])
print(result[:10])
ValueError: Expected 2D array, got 1D array instead: array=['INLAND' 'NEAR OCEAN' 'INLAND' ... '<1H OCEAN' '<1H OCEAN' 'INLAND']. Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample. |
#sklearn 의 변환기들은 2차원 배열을 요구합니다.
from sklearn.preprocessing import OrdinalEncoder
oridinalEncoder = OrdinalEncoder()
result = oridinalEncoder.fit_transform(housing_features[['ocean_proximity']])
print(result[:10])
[[1.] [4.] [1.] [4.] [0.] [3.] [0.] [0.] [0.] [0.]] |
#원 핫 인코딩 - 범주형의 개수 만큼 열을 만들어서 해당하는 열에만 1을 표시
from sklearn.preprocessing import OneHotEncoder
oneHotEncoder = OneHotEncoder()
#기본적으로 희소 행렬(sparse matrix)
result = oneHotEncoder.fit_transform(housing_features[['ocean_proximity']])
print(result[:10])
#밀집 행렬로 변환
print(result.toarray()[:10])
(0, 1) 1.0 (1, 4) 1.0 (2, 1) 1.0 (3, 4) 1.0 (4, 0) 1.0 (5, 3) 1.0 (6, 0) 1.0 (7, 0) 1.0 (8, 0) 1.0 (9, 0) 1.0 [[0. 1. 0. 0. 0.] [0. 0. 0. 0. 1.] [0. 1. 0. 0. 0.] [0. 0. 0. 0. 1.] [1. 0. 0. 0. 0.] [0. 0. 0. 1. 0.] [1. 0. 0. 0. 0.] [1. 0. 0. 0. 0.] [1. 0. 0. 0. 0.] [1. 0. 0. 0. 0.]] |
- 특성 스케일링
- 입력 숫자 특성들의 스케일이 많이 다르면 정확한 예측을 하지 못하는 경우가 발생
- 입력 숫자 특성들만 스케일링을 수행하는데 타겟의 경우는 범위가 너무 큰 경우 로그 스케일링을 한다.
- 훈련 데이터와 테스트 데이터로 분할된 경우 일반적으로 훈련 데이터에만 fit 수행하고
훈련 데이터와 테스트 데이터에 transform 수행 - min-max scaler와 standard scaler 주로 이용
- 정규화 : MinMaxScaler
- (데이터 - 최소값) / (최대값 - 최소값)
- 최대값이 이상치인 경우 영향을 많이 받게 됨
- 표준화: StandardScaler
- 먼저 평균을 뺀 후 (평균=0) 표준편차로 나눠서 분포의 분산이 1이 되도록 함
- 범위의 상한과 하한이 없어서 어느정도 값이 만들어지질지 예측하기 어려움
- 딥러닝에서는 0 ~ 1의 값만을 요구하는 경우가 있어서 사용이 불가
- 이상치의 영향을 덜 받는다. 로버스트함
- 전처리 작업을 위한 Pipeline
- 연속해서 작업 수행 - 여러 작업을 하나로 묶어서 수행하는 것
- 결측치 대체를 하고 스케일링을 수행한다고 했을 때 따로 작업을 해도 되지만 묶어서 한번에 수행 가능
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
#수행하고자 하는 작업을 이름 과 추정기를 튜플로 묶어서 list로 설정해주면 됩니다.
num_pipeline = Pipeline([
('imputer', SimpleImputer(strategy = 'median')),
('std_scaler', StandardScaler())
])
housing_num_tr = num_pipeline.fit_transform(housing_num)
print(housing_num_tr)
[[-0.94135046 1.34743822 0.02756357 ... 0.73260236 0.55628602 -0.8936472 ] [ 1.17178212 -1.19243966 -1.72201763 ... 0.53361152 0.72131799 1.292168 ] [ 0.26758118 -0.1259716 1.22045984 ... -0.67467519 -0.52440722 -0.52543365] ... [-1.5707942 1.31001828 1.53856552 ... -0.86201341 -0.86511838 -0.36547546] [-1.56080303 1.2492109 -1.1653327 ... -0.18974707 0.01061579 0.16826095] [-1.28105026 2.02567448 -0.13148926 ... -0.71232211 -0.79857323 -0.390569 ]] |
- 수행하고자 하는작업을이름과 추정기를 튜플로 묶어서 list로 설정
- ColumnTransformer
- sklearn 0.20 버전에서 추가된 변환기로 여러 특성에 다른 변환 처리를 할 수 있도록 해주는 클래스
- Pipeline과 유사하게 생성, 튜플을 만들 때 (변환기 이름, 변환기, 컬럼 이름리스트) 형태로 대입
from sklearn.compose import ColumnTransformer
#숫자 컬럼 이름 리스트
num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]
#print(num_attribs)
#열 별로 다른 변환기를 적용하기 위한 인스턴스 생성
full_pipeline = ColumnTransformer([
("num", num_pipeline, num_attribs),
("cat", OneHotEncoder(), cat_attribs)
])
#변환기 적용
hosing_prepared = full_pipeline.fit_transform(housing)
print(hosing_prepared)
[[-1.32783522 1.05254828 0.98214266 ... 0. 1. 0. ] [-1.32284391 1.04318455 -0.60701891 ... 0. 1. 0. ] [-1.33282653 1.03850269 1.85618152 ... 0. 1. 0. ] ... [-0.8237132 1.77823747 -0.92485123 ... 0. 0. 0. ] [-0.87362627 1.77823747 -0.84539315 ... 0. 0. 0. ] [-0.83369581 1.75014627 -1.00430931 ... 0. 0. 0. ]] |
#피처 전처리
housing_prepared = full_pipeline.fit_transform(housing_features)
- 모델 적용 및 테스트
- 선형 회귀 모델
#선형 회귀 모델을 이용
from sklearn.linear_model import LinearRegression
#예측 모델 인스턴스 생성
lin_reg = LinearRegression()
#훈련
lin_reg.fit(housing_prepared, housing_labels)
#테스트
some_data = housing_features.iloc[:5]
some_labels = housing_labels.iloc[:5]
#샘플 피처 전처리
some_data_prepared = full_pipeline.transform(some_data)
print("예측한 값:", lin_reg.predict(some_data_prepared))
print("실제 값:", list(some_labels))
예측한 값: [ 88983.14806384 305351.35385026 153334.71183453 184302.55162102 246840.18988841] 실제 값: [72100.0, 279600.0, 82700.0, 112500.0, 238300.0] |
- 평가 지표
- 모델을 생성하고 나면 이 모델을 다른 모델과 비교하기 위해서 평가지표 사용
- 회귀의 평가지표로 사용 - RMSE, RMAE 등
- RMSE: 예측한 값과 실제 값의 차이(residual-잔차)를 제곱해서 더한 후 제곱근을 해서 사용
- RMAE: 잔차에 절대값을 적용한 후 합계를 구한 것
- 이 값이 적은 쪽이 우수한 모델
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
#모델을 만들 때 사용한 데이터를 가지고 예측
housing_predictions = lin_reg.predict(housing_prepared)
#잔차 제곱합
lin_mse = mean_squared_error(housing_labels, housing_predictions)
lin_rmse = np.sqrt(lin_mse)
#잔차의 절대값 합
lin_mae = mean_absolute_error(housing_labels, housing_predictions)
print("잔차 제곱합:", lin_mse)
print("잔차 제곱합의 제곱근:", lin_rmse)
print("잔차 절대값합:", lin_mae)
잔차 제곱합: 4767980139.451871 잔차 제곱합의 제곱근: 69050.56219504567 잔차 절대값합: 49905.329442715316 |
- 제곱합은 단위가 너무 큼. 판정하기 어렵기 때문에 제곱근을 해서 스케일링한다.
- 집값은 120000 ~ 260000 사이가 많은데, 실제로는 7만에서 5만 차이가 나니까 잔차가 많다.
- 훈련에 사용한 데이터로 테스트 했는데 훈련에 사용한 데이터도 잘 맞지 않으면 과소 적합이라고 한다.
- 데이터를 더 수집하기
- 다른 모델(알고리즘)을 사용해보기
- 하이퍼파라미터를 조정해보기
- 훈련 데이터에는 잘 맞지만, 테스트 데이터나 새로운 데이터에 잘 맞지 않으면 과대 적합이라고 한다.
- 새로운 모델 적용
- Decision Tree
- 트리 모델은 일반적인 형태로 검증하지 않고 데이터를 K개의 그룹으로 나눈 후 (k-1)개의 데이터 그룹을 사용해서 모델을 생성하고 나머지 그룹을 이용해서 테스트 수행하고 이 작업을 k번 반복해서 그 때의 평균을 리턴한다.
- sklearn에서는 점수가 높은 쪽이 좋다고 생각하기 때문에 평가지표를 설정할 때 (-)를 곱해서 사용한다.
from sklearn.tree import DecisionTreeRegressor
tree_reg = DecisionTreeRegressor(random_state=42)
tree_reg.fit(housing_prepared, housing_labels)
housing_predictions = tree_reg.predict(housing_prepared)
tree_mse = mean_squared_error(housing_labels, housing_predictions)
tree_rmse = np.sqrt(tree_mse)
print(tree_rmse)
0.0 |
- 얜 안되겠네
- K-fold cross-validation (K 겹 교차 검증)
from sklearn.model_selection import cross_val_score
#10개의 K를 설정
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
tree_rmse_scores = np.sqrt(-scores)
print(tree_rmse_scores)
[71177.6601991 69770.07865373 64770.5639395 68536.60203993 67057.08155801 68847.12456973 70977.38255647 69208.86346929 67187.87131535 73280.38732407] |
- 그닥 별로. 오히려 나쁜듯
- 그리드 탐색
- 가장 좋은 하이퍼 파라미터를 찾는 것
- 파라미터: 함수 또는 메소드가 수행할 때 결정하는 데이터
- 하이퍼 파라미터: 사용자가 직접 설정하는 데이터
대부분의 하이퍼파라미터는 가장 알맞은 기본값을 소유하고 있다.
- GridSearchCV를 이용하면 여러종류의 하이퍼 파라미터를 설정해서 훈련한 후 가장 좋은 하이퍼 파라미터를 추천
- 파라미터를 설정할 때는 list의 dict로 설정하게 되는데 dict에 하이퍼 파라미터 이름과 값의 list를 설정하는데 하나의 dict 내에 있는 파라미터는 모든 조합을 가지고 수행하고 각 dict는 별개로 수행
- 시간이 오래 걸릴 가능성이 높음
from sklearn.ensemble import RandomForestRegressor
forest_reg = RandomForestRegressor(random_state=42)
#파라미터 조합을 생성: 12 + 6 : 18번 수행
param_grid = [{'n_estimators':[3, 10, 30], 'max_features': [2, 4, 6, 8]},
{'bootstrap':[False], 'n_estimators':[3, 10], 'max_features':[2, 3, 4]}]
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(forest_reg, param_grid, cv=5,
scoring='neg_mean_squared_error',
return_train_score=True, n_jobs=2)
grid_search.fit(housing_prepared, housing_labels)
print(grid_search.best_params_)
#내장 파라미터는 뒤에 _ 붙여야 함
{'max_features': 8, 'n_estimators': 30} |
# 평가 점수 확인
cvres = grid_search.cv_results_
for mean_score, params in zip(cvres['mean_test_score'], cvres['params']):
print(np.sqrt(-mean_score), params)
63827.76261554265 {'max_features': 2, 'n_estimators': 3} 55056.82212305312 {'max_features': 2, 'n_estimators': 10} 52673.5498401615 {'max_features': 2, 'n_estimators': 30} 60299.48845134689 {'max_features': 4, 'n_estimators': 3} 53106.41271952157 {'max_features': 4, 'n_estimators': 10} 50370.55528306362 {'max_features': 4, 'n_estimators': 30} 58363.22748437211 {'max_features': 6, 'n_estimators': 3} 52446.057900340325 {'max_features': 6, 'n_estimators': 10} 50177.91173851986 {'max_features': 6, 'n_estimators': 30} 58058.12321723554 {'max_features': 8, 'n_estimators': 3} 51849.42681935635 {'max_features': 8, 'n_estimators': 10} 49941.11534754462 {'max_features': 8, 'n_estimators': 30} 62820.05402812565 {'bootstrap': False, 'max_features': 2, 'n_estimators': 3} 53846.18083156347 {'bootstrap': False, 'max_features': 2, 'n_estimators': 10} 59026.17902108823 {'bootstrap': False, 'max_features': 3, 'n_estimators': 3} 52996.55803561763 {'bootstrap': False, 'max_features': 3, 'n_estimators': 10} 58842.47703118809 {'bootstrap': False, 'max_features': 4, 'n_estimators': 3} 51891.75100173946 {'bootstrap': False, 'max_features': 4, 'n_estimators': 10} |
#최적의 모델 가져오기
print(grid_search.best_estimator_)
RandomForestRegressor(max_features=8, n_estimators=30, random_state=42) |
- 랜덤 서치
- 그리드 서치는 파라미터 값을 직접 입력해서 선택하도록 하는데 파라미터가 적을 때는 유용하지만 많을 때는 어려움
- RandomizedSearchCV는 파라미터의 상한과 하한을
forest_reg = RandomForestRegressor(random_state=42)
from scipy.stats import randint
#파라미터 조합을 생성: 12 + 6 : 18번 수행
param_distribs = {'n_estimators':randint(low=1, high=200),
'max_features': randint(low=1, high=8)}
from sklearn.model_selection import RandomizedSearchCV
random_search = RandomizedSearchCV(forest_reg, param_distributions = param_distribs, cv=5,
scoring='neg_mean_squared_error', n_jobs=-1,
n_iter=10)
grid_search.fit(housing_prepared, housing_labels)
- 앙상블
- 여러 개의 모델을 사용하는 방식
- DecisionTree는 하나의 트리를 이용하지만 RandomForest는 여러개의 DecisionTree를 가지고 예측
- 테스트를 할 때는 모델을 만들 때 사용한 데이터가 아닌 테스트 데이터로 수행하기도 함
- Overfitting(과대적합): 훈련 데이터에 잘 맞지만 테스트 데이터에 잘 맞지 않는 상황
- Underfitting(과소적합): 훈련데이터에도 잘 맞지 않는 상황
'Python' 카테고리의 다른 글
[Python] 회귀 - 비선형 회귀 (0) | 2024.03.07 |
---|---|
[Python] 분류 (0) | 2024.03.07 |
[Python] 지도학습 연습 _ 자전거 대여 수요 예측 (0) | 2024.03.06 |
[Python] 벡터 연산에서 기억할 부분 (0) | 2024.02.27 |
[Python] 샘플링 _ 표본 추출 (1) | 2024.02.26 |