Scikit-Learn 튜토리얼: 설치 방법 및 Scikit-Learn 예제
사이킷런이란?
사이 킷 러닝 오픈 소스입니다 Python 머신 러닝을 위한 라이브러리입니다. KNN, XGBoost, 랜덤 포레스트, SVM과 같은 최첨단 알고리즘을 지원합니다. NumPy 위에 구축되었습니다. Scikit-learn은 Kaggle 대회와 저명한 기술 회사에서 널리 사용됩니다. 전처리, 차원 축소(매개변수 선택), 분류, 회귀, 클러스터링 및 모델 선택에 도움이 됩니다.
Scikit-learn은 모든 오픈 소스 라이브러리에 대한 최고의 문서를 보유하고 있습니다. 다음에서 대화형 차트를 제공합니다. https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.
Scikit-learn은 사용하기가 그리 어렵지 않으며 뛰어난 결과를 제공합니다. 그러나 scikit learn은 병렬 계산을 지원하지 않습니다. 이를 통해 딥 러닝 알고리즘을 실행할 수는 있지만 최적의 솔루션은 아닙니다. 특히 TensorFlow 사용 방법을 알고 있는 경우 더욱 그렇습니다.
Scikit-learn을 다운로드하고 설치하는 방법
이제 이것에서 Python Scikit-learn 튜토리얼에서는 Scikit-learn을 다운로드하고 설치하는 방법을 배웁니다.
옵션 AWS
scikit-learn은 AWS를 통해 사용할 수 있습니다. 제발 참조 scikit-learn이 사전 설치된 Docker 이미지입니다.
개발자 버전을 사용하려면 다음 명령을 사용하십시오. Jupyter
import sys !{sys.executable} -m pip install git+git://github.com/scikit-learn/scikit-learn.git
옵션 Mac 또는 Windows 아나콘다를 사용하여
Anaconda 설치에 대해 알아보려면 다음을 참조하세요. https://www.guru99.com/download-install-tensorflow.html
최근 scikit 개발자들은 현재 버전에서 직면한 일반적인 문제를 해결하는 개발 버전을 출시했습니다. 현재 버전보다 개발자 버전을 사용하는 것이 더 편리하다는 것을 알았습니다.
Conda 환경에서 scikit-learn을 설치하는 방법
conda 환경으로 scikit-learn을 설치한 경우 버전 0.20으로 업데이트하는 단계를 따르세요.
단계 1) 텐서플로우 환경 활성화
source activate hello-tf
단계 2) conda 명령을 사용하여 scikit 린 제거
conda remove scikit-learn
단계 3) 개발자 버전을 설치합니다.
필요한 라이브러리와 함께 scikit learn 개발자 버전을 설치하십시오.
conda install -c anaconda git pip install Cython pip install h5py pip install git+git://github.com/scikit-learn/scikit-learn.git
알림: Windows 사용자가 설치해야 합니다 Microsoft 시각 C++ 14. 다음에서 얻을 수 있습니다. LINK
기계 학습을 사용한 Scikit-Learn 예
이 Scikit 튜토리얼은 두 부분으로 나누어져 있습니다:
- scikit-learn을 사용한 머신러닝
- LIME으로 모델을 신뢰하는 방법
첫 번째 부분에서는 파이프라인을 구축하고, 모델을 만들고, 하이퍼파라미터를 조정하는 방법을 자세히 설명하고, 두 번째 부분에서는 모델 선택 측면에서 최신 기술을 제공합니다.
1단계) 데이터 가져오기
이 Scikit 학습 튜토리얼에서는 성인 데이터 세트를 사용하게 됩니다.
이 데이터 세트의 배경 정보는 기술 통계에 대해 더 자세히 알고 싶다면 다이브 및 개요 도구를 사용하십시오.
참조 이 튜토리얼 다이빙 및 개요에 대해 자세히 알아보기
Pandas를 사용하여 데이터세트를 가져옵니다. 연속형 변수의 유형을 부동 소수점 형식으로 변환해야 한다는 점에 유의하세요.
이 데이터 세트에는 XNUMX개의 범주형 변수가 포함되어 있습니다.
범주형 변수는 CATE_FEATURES에 나열되어 있습니다.
- 작업반
- 교육
- 결혼의
- 직업
- 관계
- 경주
- 섹스
- 원주민_국가
또한 XNUMX개의 연속 변수:
연속 변수는 CONTI_FEATURES에 나열됩니다.
- 나이
- fnlwgt
- education_num
- 자본 이득
- 자본 손실
- 시간_주
어떤 열을 사용하고 있는지 더 잘 알 수 있도록 목록을 직접 작성한다는 점에 유의하세요. 범주형 또는 연속형 목록을 구성하는 더 빠른 방법은 다음을 사용하는 것입니다.
## List Categorical CATE_FEATURES = df_train.iloc[:,:-1].select_dtypes('object').columns print(CATE_FEATURES) ## List continuous CONTI_FEATURES = df_train._get_numeric_data() print(CONTI_FEATURES)
데이터를 가져오는 코드는 다음과 같습니다.
# Import dataset import pandas as pd ## Define path data COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label'] ### Define continuous list CONTI_FEATURES = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week'] ### Define categorical list CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country'] ## Prepare the data features = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data" df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False) df_train[CONTI_FEATURES] =df_train[CONTI_FEATURES].astype('float64') df_train.describe()
나이 | fnlwgt | education_num | 자본 이득 | 자본 손실 | 시간_주 | |
---|---|---|---|---|---|---|
계산 | 32561.000000 | 3.256100e + 04 | 32561.000000 | 32561.000000 | 32561.000000 | 32561.000000 |
평균 | 38.581647 | 1.897784e + 05 | 10.080679 | 1077.648844 | 87.303830 | 40.437456 |
표준 | 13.640433 | 1.055500e + 05 | 2.572720 | 7385.292085 | 402.960219 | 12.347429 |
분 | 17.000000 | 1.228500e + 04 | 1.000000 | 0.000000 | 0.000000 | 1.000000 |
25% | 28.000000 | 1.178270e + 05 | 9.000000 | 0.000000 | 0.000000 | 40.000000 |
50% | 37.000000 | 1.783560e + 05 | 10.000000 | 0.000000 | 0.000000 | 40.000000 |
75% | 48.000000 | 2.370510e + 05 | 12.000000 | 0.000000 | 0.000000 | 45.000000 |
최대 | 90.000000 | 1.484705e + 06 | 16.000000 | 99999.000000 | 4356.000000 | 99.000000 |
Native_country 특성의 고유값 개수를 확인할 수 있습니다. 네덜란드-네덜란드 출신 가구는 한 가구뿐임을 알 수 있습니다. 이 가정은 우리에게 어떤 정보도 제공하지 않지만 훈련 중에 오류가 발생합니다.
df_train.native_country.value_counts()
United-States 29170 Mexico 643 ? 583 Philippines 198 Germany 137 Canada 121 Puerto-Rico 114 El-Salvador 106 India 100 Cuba 95 England 90 Jamaica 81 South 80 China 75 Italy 73 Dominican-Republic 70 Vietnam 67 Guatemala 64 Japan 62 Poland 60 Columbia 59 Taiwan 51 Haiti 44 Iran 43 Portugal 37 Nicaragua 34 Peru 31 France 29 Greece 29 Ecuador 28 Ireland 24 Hong 20 Cambodia 19 Trinadad&Tobago 19 Thailand 18 Laos 18 Yugoslavia 16 Outlying-US(Guam-USVI-etc) 14 Honduras 13 Hungary 13 Scotland 12 Holand-Netherlands 1 Name: native_country, dtype: int64
정보가 없는 이 행을 데이터세트에서 제외할 수 있습니다.
## Drop Netherland, because only one row df_train = df_train[df_train.native_country != "Holand-Netherlands"]
다음으로 연속 기능의 위치를 목록에 저장합니다. 파이프라인을 빌드하려면 다음 단계에서 필요합니다.
아래 코드는 CONTI_FEATURES의 모든 열 이름을 반복하고 해당 위치(즉, 해당 번호)를 가져온 다음 이를 conti_features라는 목록에 추가합니다.
## Get the column index of the categorical features conti_features = [] for i in CONTI_FEATURES: position = df_train.columns.get_loc(i) conti_features.append(position) print(conti_features)
[0, 2, 10, 4, 11, 12]
아래 코드는 위와 동일한 작업을 수행하지만 범주형 변수에 대해 수행합니다. 아래 코드는 범주형 기능을 제외하고 이전에 수행한 작업을 반복합니다.
## Get the column index of the categorical features categorical_features = [] for i in CATE_FEATURES: position = df_train.columns.get_loc(i) categorical_features.append(position) print(categorical_features)
[1, 3, 5, 6, 7, 8, 9, 13]
데이터 세트를 살펴볼 수 있습니다. 각 범주형 특성은 문자열입니다. 문자열 값으로 모델을 공급할 수 없습니다. 더미 변수를 사용하여 데이터세트를 변환해야 합니다.
df_train.head(5)
실제로 기능의 각 그룹에 대해 하나의 열을 생성해야 합니다. 먼저 아래 코드를 실행하여 필요한 총 열 수를 계산할 수 있습니다.
print(df_train[CATE_FEATURES].nunique(), 'There are',sum(df_train[CATE_FEATURES].nunique()), 'groups in the whole dataset')
workclass 9 education 16 marital 7 occupation 15 relationship 6 race 5 sex 2 native_country 41 dtype: int64 There are 101 groups in the whole dataset
전체 데이터 세트에는 위에 표시된 대로 101개의 그룹이 포함되어 있습니다. 예를 들어, workclass의 피처에는 XNUMX개의 그룹이 있습니다. 다음 코드로 그룹 이름을 시각화할 수 있습니다.
Unique()는 범주형 특성의 고유한 값을 반환합니다.
for i in CATE_FEATURES: print(df_train[i].unique())
['State-gov' 'Self-emp-not-inc' 'Private' 'Federal-gov' 'Local-gov' '?' 'Self-emp-inc' 'Without-pay' 'Never-worked'] ['Bachelors' 'HS-grad' '11th' 'Masters' '9th' 'Some-college' 'Assoc-acdm' 'Assoc-voc' '7th-8th' 'Doctorate' 'Prof-school' '5th-6th' '10th' '1st-4th' 'Preschool' '12th'] ['Never-married' 'Married-civ-spouse' 'Divorced' 'Married-spouse-absent' 'Separated' 'Married-AF-spouse' 'Widowed'] ['Adm-clerical' 'Exec-managerial' 'Handlers-cleaners' 'Prof-specialty' 'Other-service' 'Sales' 'Craft-repair' 'Transport-moving' 'Farming-fishing' 'Machine-op-inspct' 'Tech-support' '?' 'Protective-serv' 'Armed-Forces' 'Priv-house-serv'] ['Not-in-family' 'Husband' 'Wife' 'Own-child' 'Unmarried' 'Other-relative'] ['White' 'Black' 'Asian-Pac-Islander' 'Amer-Indian-Eskimo' 'Other'] ['Male' 'Female'] ['United-States' 'Cuba' 'Jamaica' 'India' '?' 'Mexico' 'South' 'Puerto-Rico' 'Honduras' 'England' 'Canada' 'Germany' 'Iran' 'Philippines' 'Italy' 'Poland' 'Columbia' 'Cambodia' 'Thailand' 'Ecuador' 'Laos' 'Taiwan' 'Haiti' 'Portugal' 'Dominican-Republic' 'El-Salvador' 'France' 'Guatemala' 'China' 'Japan' 'Yugoslavia' 'Peru' 'Outlying-US(Guam-USVI-etc)' 'Scotland' 'Trinadad&Tobago' 'Greece' 'Nicaragua' 'Vietnam' 'Hong' 'Ireland' 'Hungary']
따라서 훈련 데이터 세트에는 101 + 7개의 열이 포함됩니다. 마지막 XNUMX개 열은 연속 특성입니다.
Scikit-learn은 변환을 처리할 수 있습니다. 이는 두 단계로 수행됩니다.
- 먼저 문자열을 ID로 변환해야 합니다. 예를 들어 State-gov의 ID는 1, Self-emp-not-inc ID는 2 등입니다. LabelEncoder 함수가 이 작업을 수행합니다.
- 각 ID를 새 열로 전치합니다. 앞서 언급했듯이 데이터 세트에는 101개 그룹의 ID가 있습니다. 따라서 모든 범주형 피처 그룹을 캡처하는 101개 열이 있습니다. Scikit-learn에는 이 작업을 수행하는 OneHotEncoder라는 함수가 있습니다.
2단계) 열차/테스트 세트 생성
이제 데이터세트가 준비되었으므로 80/20으로 나눌 수 있습니다.
훈련 세트의 경우 80%, 테스트 세트의 경우 20%입니다.
train_test_split을 사용할 수 있습니다. 첫 번째 인수는 데이터 프레임이 기능이고 두 번째 인수는 레이블 데이터 프레임입니다. test_size를 사용하여 테스트 세트의 크기를 지정할 수 있습니다.
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(df_train[features], df_train.label, test_size = 0.2, random_state=0) X_train.head(5) print(X_train.shape, X_test.shape)
(26048, 14) (6512, 14)
3단계) 파이프라인 구축
파이프라인을 사용하면 모델에 일관된 데이터를 더 쉽게 제공할 수 있습니다.
이 아이디어는 원시 데이터를 '파이프라인'에 넣어 작업을 수행하는 것입니다.
예를 들어, 현재 데이터 집합을 사용하면 연속 변수를 표준화하고 범주형 데이터를 변환해야 합니다. 파이프라인 내에서 모든 작업을 수행할 수 있습니다. 예를 들어, 데이터 집합에 'NA'가 있는 경우 평균이나 중앙값으로 대체할 수 있습니다. 새 변수를 만들 수도 있습니다.
당신에게는 선택권이 있습니다. 두 프로세스를 하드 코딩하거나 파이프라인을 생성합니다. 첫 번째 선택은 데이터 유출로 이어질 수 있으며 시간이 지남에 따라 불일치가 발생할 수 있습니다. 더 나은 옵션은 파이프라인을 사용하는 것입니다.
from sklearn.preprocessing import StandardScaler, OneHotEncoder, LabelEncoder from sklearn.compose import ColumnTransformer, make_column_transformer from sklearn.pipeline import make_pipeline from sklearn.linear_model import LogisticRegression
파이프라인은 물류 분류기를 공급하기 전에 두 가지 작업을 수행합니다.
- 변수 표준화: `StandardScaler()'
- 범주형 기능 변환: OneHotEncoder(sparse=False)
make_column_transformer를 사용하여 두 단계를 수행할 수 있습니다. 이 기능은 현재 버전의 scikit-learn(0.19)에서는 사용할 수 없습니다. 현재 버전에서는 파이프라인에서 레이블 인코더와 하나의 핫 인코더를 수행하는 것이 불가능합니다. 이것이 우리가 개발자 버전을 사용하기로 결정한 이유 중 하나입니다.
make_column_transformer는 사용하기 쉽습니다. 변환을 적용할 열과 작동할 변환을 정의해야 합니다. 예를 들어, 연속 피처를 표준화하려면 다음을 수행할 수 있습니다.
- make_column_transformer 내부의 conti_features, StandardScaler().
- conti_features: 연속 변수 목록
- StandardScaler: 변수 표준화
make_column_transformer 내부의 OneHotEncoder 개체는 자동으로 레이블을 인코딩합니다.
preprocess = make_column_transformer( (conti_features, StandardScaler()), ### Need to be numeric not string to specify columns name (categorical_features, OneHotEncoder(sparse=False)) )
파이프라인이 fit_transform으로 작동하는지 테스트할 수 있습니다. 데이터 세트는 다음 모양이어야 합니다: 26048, 107
preprocess.fit_transform(X_train).shape
(26048, 107)
데이터 변환기를 사용할 준비가 되었습니다. make_pipeline을 사용하여 파이프라인을 생성할 수 있습니다. 데이터가 변환되면 로지스틱 회귀 분석을 제공할 수 있습니다.
model = make_pipeline( preprocess, LogisticRegression())
scikit-learn을 사용하여 모델을 훈련하는 것은 간단합니다. 파이프라인, 즉 모델 뒤에 오는 개체 맞춤을 사용해야 합니다. scikit-learn 라이브러리의 점수 개체를 사용하여 정확도를 인쇄할 수 있습니다.
model.fit(X_train, y_train) print("logistic regression score: %f" % model.score(X_test, y_test))
logistic regression score: 0.850891
마지막으로, Predict_proba를 사용하여 클래스를 예측할 수 있습니다. 각 클래스에 대한 확률을 반환합니다. 합하면 XNUMX이 된다는 점에 유의하세요.
model.predict_proba(X_test)
array([[0.83576663, 0.16423337], [0.94582765, 0.05417235], [0.64760587, 0.35239413], ..., [0.99639252, 0.00360748], [0.02072181, 0.97927819], [0.56781353, 0.43218647]])
4단계) 그리드 검색에서 파이프라인 사용
하이퍼파라미터(숨겨진 유닛과 같이 네트워크 구조를 결정하는 변수)를 조정하는 것은 지루하고 지칠 수 있습니다.
모델을 평가하는 한 가지 방법은 훈련 세트의 크기를 변경하고 성능을 평가하는 것입니다.
이 방법을 XNUMX번 반복하여 점수 측정항목을 볼 수 있습니다. 그러나 그것은 너무 많은 일이다.
대신 scikit-learn은 매개변수 조정 및 교차 검증을 수행하는 기능을 제공합니다.
교차 검증
교차 검증이란 훈련 중에 훈련 세트가 n번 접힌 후 모델을 n번 평가한다는 것을 의미합니다. 예를 들어, cv가 10으로 설정되면 훈련 세트는 훈련되고 10번 평가됩니다. 각 라운드에서 분류자는 모델을 훈련하기 위해 무작위로 XNUMX개의 접기를 선택하고, XNUMX번째 접기는 평가용입니다.
그리드 검색
각 분류자에는 조정할 하이퍼파라미터가 있습니다. 다른 값을 시도하거나 매개변수 그리드를 설정할 수 있습니다. scikit-learn 공식 웹사이트에 가면 로지스틱 분류기에 조정할 매개변수가 다른 것을 볼 수 있습니다. 훈련 속도를 높이려면 C 매개변수를 조정하도록 선택합니다. 정규화 매개변수를 제어합니다. 긍정적이어야 합니다. 값이 작을수록 정규화 프로그램에 더 많은 가중치를 부여합니다.
GridSearchCV 개체를 사용할 수 있습니다. 조정할 하이퍼파라미터가 포함된 사전을 생성해야 합니다.
초매개변수와 그 뒤에 시도하려는 값을 나열합니다. 예를 들어 C 매개변수를 조정하려면 다음을 사용합니다.
- 'logisticregression__C': [0.1, 1.0, 1.0]: 매개변수 앞에는 분류자의 이름(소문자)과 두 개의 밑줄이 옵니다.
모델은 0.001, 0.01, 0.1, 1의 네 가지 값을 시도합니다.
10개의 접기를 사용하여 모델을 훈련합니다: cv=10
from sklearn.model_selection import GridSearchCV # Construct the parameter grid param_grid = { 'logisticregression__C': [0.001, 0.01,0.1, 1.0], }
gri 및 cv 매개변수와 함께 GridSearchCV를 사용하여 모델을 훈련할 수 있습니다.
# Train the model grid_clf = GridSearchCV(model, param_grid, cv=10, iid=False) grid_clf.fit(X_train, y_train)
출력
GridSearchCV(cv=10, error_score='raise-deprecating', estimator=Pipeline(memory=None, steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None, transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...ty='l2', random_state=None, solver='liblinear', tol=0.0001, verbose=0, warm_start=False))]), fit_params=None, iid=False, n_jobs=1, param_grid={'logisticregression__C': [0.001, 0.01, 0.1, 1.0]}, pre_dispatch='2*n_jobs', refit=True, return_train_score='warn', scoring=None, verbose=0)
최상의 매개변수에 액세스하려면 best_params_를 사용합니다.
grid_clf.best_params_
출력
{'logisticregression__C': 1.0}
XNUMX가지 서로 다른 정규화 값으로 모델을 훈련한 후 최적의 매개변수는 다음과 같습니다.
print("best logistic regression from grid search: %f" % grid_clf.best_estimator_.score(X_test, y_test))
그리드 검색에서 가장 좋은 로지스틱 회귀: 0.850891
예측 확률에 액세스하려면 다음을 수행하세요.
grid_clf.best_estimator_.predict_proba(X_test)
array([[0.83576677, 0.16423323], [0.9458291 , 0.0541709 ], [0.64760416, 0.35239584], ..., [0.99639224, 0.00360776], [0.02072033, 0.97927967], [0.56782222, 0.43217778]])
scikit-learn을 사용한 XGBoost 모델
시장에서 최고의 분류기 중 하나를 훈련시키기 위해 Scikit-learn 예제를 시도해 보겠습니다. XGBoost는 Random Forest보다 개선되었습니다. 본 범위를 벗어나는 분류기의 이론적 배경 Python 사이킷 튜토리얼. XGBoost는 많은 캐글 대회에서 우승했다는 점을 명심하세요. 평균 데이터 세트 크기를 사용하면 딥 러닝 알고리즘만큼 훌륭하거나 더 나은 성능을 발휘할 수 있습니다.
분류기는 조정할 매개변수 수가 많기 때문에 훈련하기가 어렵습니다. 물론 GridSearchCV를 사용하여 매개변수를 선택할 수도 있습니다.
대신, 최적의 매개변수를 찾는 더 나은 방법을 사용하는 방법을 살펴보겠습니다. GridSearchCV는 많은 값을 전달하는 경우 학습하는 데 지루하고 시간이 매우 오래 걸릴 수 있습니다. 검색 공간은 매개변수 수에 따라 증가합니다. 선호되는 솔루션은 RandomizedSearchCV를 사용하는 것입니다. 이 방법은 각 반복 후에 각 하이퍼파라미터의 값을 무작위로 선택하는 것으로 구성됩니다. 예를 들어 분류기가 1000번 이상 반복 학습되면 1000개의 조합이 평가됩니다. 그것은 다소 비슷하게 작동합니다. 그리드검색CV
xgboost를 가져와야 합니다. 라이브러리가 설치되지 않은 경우 pip3 install xgboost를 사용하거나
use import sys !{sys.executable} -m pip install xgboost
In Jupyter 환경
다음으로,
import xgboost from sklearn.model_selection import RandomizedSearchCV from sklearn.model_selection import StratifiedKFold
이 Scikit의 다음 단계 Python 튜토리얼에는 조정할 매개변수 지정이 포함되어 있습니다. 튜닝할 모든 매개변수를 보려면 공식 문서를 참조하세요. 위해 Python Sklearn 튜토리얼에서는 각각 두 개의 값을 가진 두 개의 하이퍼 매개변수만 선택합니다. XGBoost는 훈련하는 데 많은 시간이 걸리며, 그리드에 하이퍼파라미터가 많을수록 기다려야 하는 시간이 길어집니다.
params = { 'xgbclassifier__gamma': [0.5, 1], 'xgbclassifier__max_depth': [3, 4] }
XGBoost 분류기를 사용하여 새로운 파이프라인을 구성합니다. 600개의 추정자를 정의하도록 선택합니다. n_estimators는 조정할 수 있는 매개변수라는 점에 유의하세요. 값이 높으면 과적합이 발생할 수 있습니다. 다른 값을 직접 시도할 수 있지만 시간이 많이 걸릴 수 있다는 점을 알아두세요. 다른 매개변수에는 기본값을 사용합니다.
model_xgb = make_pipeline( preprocess, xgboost.XGBClassifier( n_estimators=600, objective='binary:logistic', silent=True, nthread=1) )
Stratified K-Folds 교차 검증기를 사용하면 교차 검증을 개선할 수 있습니다. 여기서는 계산 속도를 높이지만 품질을 낮추기 위해 세 개의 접기만 구성합니다. 결과를 개선하려면 집에서 이 값을 5 또는 10으로 늘리십시오.
XNUMX번의 반복을 통해 모델을 훈련하도록 선택합니다.
skf = StratifiedKFold(n_splits=3, shuffle = True, random_state = 1001) random_search = RandomizedSearchCV(model_xgb, param_distributions=params, n_iter=4, scoring='accuracy', n_jobs=4, cv=skf.split(X_train, y_train), verbose=3, random_state=1001)
무작위 검색을 사용할 준비가 되었습니다. 모델을 훈련할 수 있습니다.
#grid_xgb = GridSearchCV(model_xgb, params, cv=10, iid=False) random_search.fit(X_train, y_train)
Fitting 3 folds for each of 4 candidates, totalling 12 fits [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8759645283888057, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8729701715996775, total= 1.0min [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8706519235199263, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8735460094437406, total= 1.3min [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8722791661868018, total= 57.7s [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8753886905447426, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8697304768486523, total= 1.3min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8740066797189912, total= 1.4min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8707671043538355, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8729701715996775, total= 1.2min [Parallel(n_jobs=4)]: Done 10 out of 12 | elapsed: 3.6min remaining: 43.5s [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8736611770125533, total= 1.2min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8692697535130154, total= 1.2min
[Parallel(n_jobs=4)]: Done 12 out of 12 | elapsed: 3.6min finished /Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/model_selection/_search.py:737: DeprecationWarning: The default of the `iid` parameter will change from True to False in version 0.22 and will be removed in 0.24. This will change numeric results when test-set sizes are unequal. DeprecationWarning)
RandomizedSearchCV(cv=<generator object _BaseKFold.split at 0x1101eb830>, error_score='raise-deprecating', estimator=Pipeline(memory=None, steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None, transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,... reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=1))]), fit_params=None, iid='warn', n_iter=4, n_jobs=4, param_distributions={'xgbclassifier__gamma': [0.5, 1], 'xgbclassifier__max_depth': [3, 4]}, pre_dispatch='2*n_jobs', random_state=1001, refit=True, return_train_score='warn', scoring='accuracy', verbose=3)
보시다시피 XGBoost는 이전 로지스틱 회귀보다 더 나은 점수를 받았습니다.
print("최고의 parameter", random_search.best_params_) print("best logistic regression from grid search: %f" % random_search.best_estimator_.score(X_test, y_test))
최고의 parameter {'xgbclassifier__max_depth': 3, 'xgbclassifier__gamma': 0.5} best logistic regression from grid search: 0.873157
random_search.best_estimator_.predict(X_test)
array(['<=50K', '<=50K', '<=50K', ..., '<=50K', '>50K', '<=50K'], dtype=object)
scikit-learn에서 MLPClassifier를 사용하여 DNN 생성
마지막으로 scikit-learn을 사용하여 딥러닝 알고리즘을 훈련할 수 있습니다. 방법은 다른 분류기와 동일합니다. 분류기는 MLPClassifier에서 사용할 수 있습니다.
from sklearn.neural_network import MLPClassifier
다음과 같은 딥러닝 알고리즘을 정의합니다.
- 아담 솔버
- Relu 활성화 기능
- 알파 = 0.0001
- 배치 크기 150
- 뉴런이 각각 100개와 50개 있는 XNUMX개의 은닉층
model_dnn = make_pipeline( preprocess, MLPClassifier(solver='adam', alpha=0.0001, activation='relu', batch_size=150, hidden_layer_sizes=(200, 100), random_state=1))
모델을 개선하기 위해 레이어 수를 변경할 수 있습니다.
model_dnn.fit(X_train, y_train) print("DNN regression score: %f" % model_dnn.score(X_test, y_test))
DNN 회귀 점수: 0.821253
LIME: 모델을 믿으세요
이제 좋은 모델이 있으므로 이를 신뢰할 수 있는 도구가 필요합니다. 기계 학습 알고리즘, 특히 랜덤 포레스트와 신경망은 블랙박스 알고리즘으로 알려져 있습니다. 다르게 말하면, 작동하지만 아무도 이유를 모릅니다.
세 명의 연구자가 컴퓨터가 어떻게 예측하는지 확인할 수 있는 훌륭한 도구를 고안했습니다. 논문 제목은 '나는 왜 당신을 믿어야 할까요?'입니다.
그들은 다음과 같은 알고리즘을 개발했습니다. LIME(로컬 해석 가능 모델 불가지론적 설명).
예를 들어 :
때로는 기계 학습 예측을 신뢰할 수 있는지 알 수 없습니다.
예를 들어, 의사는 컴퓨터가 그렇게 말했다는 이유만으로 진단을 신뢰할 수 없습니다. 또한 모델을 생산에 투입하기 전에 모델을 신뢰할 수 있는지도 알아야 합니다.
어떤 분류기가 신경망, 랜덤 포레스트, 커널이 포함된 SVM과 같은 믿을 수 없을 정도로 복잡한 모델에서도 왜 분류자가 예측을 하는지 이해할 수 있다고 상상해 보세요.
예측의 이면에 있는 이유를 이해할 수 있다면 예측을 신뢰하기가 더 쉬워질 것입니다. 의사의 예에서 모델이 어떤 증상이 필수적인지 말해 주면 신뢰할 수 있으며, 모델을 신뢰해서는 안 되는지 파악하는 것도 더 쉽습니다.
Lime은 어떤 특징이 분류기의 결정에 영향을 미치는지 알려줄 수 있습니다.
데이터 준비
LIME을 실행하기 위해 변경해야 할 몇 가지 사항은 다음과 같습니다. 파이썬. 우선 터미널에 라임을 설치해야 합니다. pip install 라임을 사용할 수 있습니다
Lime은 LimeTabularExplainer 개체를 사용하여 로컬에서 모델을 근사화합니다. 이 개체에는 다음이 필요합니다.
- numpy 형식의 데이터 세트
- 기능 이름: feature_names
- 클래스 이름: class_names
- 범주형 기능 열의 인덱스: categorical_features
- 각 범주형 기능에 대한 그룹 이름: categorical_names
numpy 기차 세트 만들기
pandas에서 df_train을 복사하여 다음으로 변환할 수 있습니다. numpy 아주 쉽게
df_train.head(5) # Create numpy data df_lime = df_train df_lime.head(3)
수업 이름 가져오기 레이블은 Unique() 개체를 사용하여 액세스할 수 있습니다. 넌 봐야 해:
- '<= 50K'
- '> 50'
# Get the class name class_names = df_lime.label.unique() class_names
array(['<=50K', '>50K'], dtype=object)
범주형 특성 열의 인덱스
그룹 이름을 얻기 위해 이전에 배웠던 방법을 사용할 수 있습니다. LabelEncoder로 레이블을 인코딩합니다. 모든 범주형 피처에서 작업을 반복합니다.
## import sklearn.preprocessing as preprocessing categorical_names = {} for feature in CATE_FEATURES: le = preprocessing.LabelEncoder() le.fit(df_lime[feature]) df_lime[feature] = le.transform(df_lime[feature]) categorical_names[feature] = le.classes_ print(categorical_names)
{'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private', 'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'], dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th', 'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad', 'Masters', 'Preschool', 'Prof-school', 'Some-college'], dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse', 'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'], dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair', 'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners', 'Machine-op-inspct', 'Other-service', 'Priv-house-serv', 'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support', 'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child', 'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other', 'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba', 'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England', 'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras', 'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica', 'Japan', 'Laos', 'Mexico', 'Nicaragua', 'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland', 'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan', 'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam', 'Yugoslavia'], dtype=object)} df_lime.dtypes
age float64 workclass int64 fnlwgt float64 education int64 education_num float64 marital int64 occupation int64 relationship int64 race int64 sex int64 capital_gain float64 capital_loss float64 hours_week float64 native_country int64 label object dtype: object
이제 데이터 세트가 준비되었으므로 아래 Scikit 학습 예제에 표시된 대로 다양한 데이터 세트를 구성할 수 있습니다. LIME의 오류를 방지하기 위해 실제로 파이프라인 외부에서 데이터를 변환합니다. LimeTabularExplainer의 훈련 세트는 문자열이 없는 numpy 배열이어야 합니다. 위의 방법을 사용하면 훈련 데이터 세트가 이미 변환되었습니다.
from sklearn.model_selection import train_test_split X_train_lime, X_test_lime, y_train_lime, y_test_lime = train_test_split(df_lime[features], df_lime.label, test_size = 0.2, random_state=0) X_train_lime.head(5)
XGBoost에서 최적의 매개변수를 사용하여 파이프라인을 만들 수 있습니다.
model_xgb = make_pipeline( preprocess, xgboost.XGBClassifier(max_depth = 3, gamma = 0.5, n_estimators=600, objective='binary:logistic', silent=True, nthread=1)) model_xgb.fit(X_train_lime, y_train_lime)
/Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/preprocessing/_encoders.py:351: FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values. If you want the future behavior and silence this warning, you can specify "categories='auto'."In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly. warnings.warn(msg, FutureWarning)
Pipeline(memory=None, steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None, transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,... reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=1))])
경고가 표시됩니다. 경고에서는 파이프라인 전에 레이블 인코더를 만들 필요가 없다고 설명합니다. LIME을 사용하고 싶지 않다면 Scikit-learn을 사용한 머신 러닝 튜토리얼의 첫 번째 부분에서 나온 방법을 사용해도 됩니다. 그렇지 않으면 이 방법을 계속 사용할 수 있으며, 먼저 인코딩된 데이터 세트를 만들고 파이프라인 내에서 get the hot one 인코더를 설정합니다.
print("best logistic regression from grid search: %f" % model_xgb.score(X_test_lime, y_test_lime))
best logistic regression from grid search: 0.873157
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01], [9.5173013e-01, 4.8269872e-02], [7.9344827e-01, 2.0655173e-01], ..., [9.9031430e-01, 9.6856682e-03], [6.4581633e-04, 9.9935418e-01], [9.7104281e-01, 2.8957171e-02]], dtype=float32)
LIME을 실제로 사용하기 전에 잘못된 분류의 특징을 담은 numpy 배열을 만들어 보겠습니다. 나중에 이 목록을 사용하여 분류기를 오도한 것이 무엇인지 파악할 수 있습니다.
temp = pd.concat([X_test_lime, y_test_lime], axis= 1) temp['predicted'] = model_xgb.predict(X_test_lime) temp['wrong']= temp['label'] != temp['predicted'] temp = temp.query('wrong==True').drop('wrong', axis=1) temp= temp.sort_values(by=['label']) temp.shape
(826, 16)
새 데이터가 포함된 모델에서 예측을 검색하는 람다 함수를 만듭니다. 곧 필요할 것입니다.
predict_fn = lambda x: model_xgb.predict_proba(x).astype(float) X_test_lime.dtypes
age float64 workclass int64 fnlwgt float64 education int64 education_num float64 marital int64 occupation int64 relationship int64 race int64 sex int64 capital_gain float64 capital_loss float64 hours_week float64 native_country int64 dtype: object
predict_fn(X_test_lime)
array([[7.96461046e-01, 2.03538969e-01], [9.51730132e-01, 4.82698716e-02], [7.93448269e-01, 2.06551731e-01], ..., [9.90314305e-01, 9.68566816e-03], [6.45816326e-04, 9.99354184e-01], [9.71042812e-01, 2.89571714e-02]])
팬더 데이터프레임을 numpy 배열로 변환합니다.
X_train_lime = X_train_lime.values X_test_lime = X_test_lime.values X_test_lime
array([[4.00000e+01, 5.00000e+00, 1.93524e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01], [2.70000e+01, 4.00000e+00, 2.16481e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01], [2.50000e+01, 4.00000e+00, 2.56263e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01], ..., [2.80000e+01, 6.00000e+00, 2.11032e+05, ..., 0.00000e+00, 4.00000e+01, 2.50000e+01], [4.40000e+01, 4.00000e+00, 1.67005e+05, ..., 0.00000e+00, 6.00000e+01, 3.80000e+01], [5.30000e+01, 4.00000e+00, 2.57940e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01]])
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01], [9.5173013e-01, 4.8269872e-02], [7.9344827e-01, 2.0655173e-01], ..., [9.9031430e-01, 9.6856682e-03], [6.4581633e-04, 9.9935418e-01], [9.7104281e-01, 2.8957171e-02]], dtype=float32)
print(features, class_names, categorical_features, categorical_names)
['age', 'workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] ['<=50K' '>50K'] [1, 3, 5, 6, 7, 8, 9, 13] {'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private', 'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'], dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th', 'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad', 'Masters', 'Preschool', 'Prof-school', 'Some-college'], dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse', 'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'], dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair', 'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners', 'Machine-op-inspct', 'Other-service', 'Priv-house-serv', 'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support', 'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child', 'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other', 'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba', 'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England', 'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras', 'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica', 'Japan', 'Laos', 'Mexico', 'Nicaragua', 'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland', 'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan', 'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam', 'Yugoslavia'], dtype=object)}
import lime import lime.lime_tabular ### Train should be label encoded not one hot encoded explainer = lime.lime_tabular.LimeTabularExplainer(X_train_lime , feature_names = features, class_names=class_names, categorical_features=categorical_features, categorical_names=categorical_names, kernel_width=3)
테스트 세트에서 임의의 가구를 선택하고 모델 예측과 컴퓨터가 어떻게 선택했는지 살펴보겠습니다.
import numpy as np np.random.seed(1) i = 100 print(y_test_lime.iloc[i]) >50K
X_test_lime[i]
array([4.20000e+01, 4.00000e+00, 1.76286e+05, 7.00000e+00, 1.20000e+01, 2.00000e+00, 4.00000e+00, 0.00000e+00, 4.00000e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 4.00000e+01, 3.80000e+01])
explain_instance와 함께 explainer를 사용하여 모델 뒤에 있는 설명을 확인할 수 있습니다.
exp = explainer.explain_instance(X_test_lime[i], predict_fn, num_features=6) exp.show_in_notebook(show_all=False)
분류기가 가구를 올바르게 예측했음을 알 수 있습니다. 실제로 수입은 50만원이 넘습니다.
우리가 말할 수 있는 첫 번째 것은 분류기가 예측 확률에 대해 그렇게 확신하지 못한다는 것입니다. 기계는 가구의 소득이 50달러를 넘을 것이라고 64%의 확률로 예측합니다. 이 64%는 자본 이득과 결혼으로 구성됩니다. 파란색은 긍정적 클래스에 부정적으로 기여하고 주황색 선은 긍정적으로 기여합니다.
분류자는 혼란스럽습니다. 이 가구의 자본 이득은 40인 반면 자본 이득은 일반적으로 부의 좋은 예측 지표이기 때문입니다. 게다가, 이 가구는 주당 XNUMX시간 미만으로 일합니다. 나이, 직업, 성별은 분류자에 긍정적으로 기여합니다.
결혼 상태가 미혼인 경우 분류기는 50달러 미만의 소득을 예측했을 것입니다(0.64-0.18 = 0.46)
잘못 분류된 다른 가구를 시도해 볼 수 있습니다.
temp.head(3) temp.iloc[1,:-2]
age 58 workclass 4 fnlwgt 68624 education 11 education_num 9 marital 2 occupation 4 relationship 0 race 4 sex 1 capital_gain 0 capital_loss 0 hours_week 45 native_country 38 Name: 20931, dtype: object
i = 1 print('This observation is', temp.iloc[i,-2:])
This observation is label <=50K predicted >50K Name: 20931, dtype: object
exp = explainer.explain_instance(temp.iloc[1,:-2], predict_fn, num_features=6) exp.show_in_notebook(show_all=False)
분류자는 소득이 50 미만일 것으로 예측했지만 이는 사실이 아닙니다. 이 집은 이상한 것 같아요. 자본 이득도 없고 자본 손실도 없습니다. 그는 이혼했고 60세이며 교육받은 사람들입니다. 즉, education_num > 12입니다. 전반적인 패턴에 따르면 이 가구는 분류자의 설명처럼 50 미만의 소득을 얻어야 합니다.
LIME을 가지고 놀려고 합니다. 분류기의 심각한 실수를 발견하게 될 것입니다.
라이브러리 소유자의 GitHub를 확인할 수 있습니다. 이미지 및 텍스트 분류에 대한 추가 문서를 제공합니다.
요약
다음은 scikit learn 버전이 0.20보다 큰 몇 가지 유용한 명령 목록입니다.
학습/테스트 데이터세트 생성 | 연습생 분할 |
파이프라인 구축 | |
열을 선택하고 변환을 적용합니다. | makecolumn변압기 |
변환 유형 | |
표준화하다 | 표준 스케일러 |
최소 최대 | 최소 최대 스케일러 |
정규화 | 노멀 라이저 |
결측값 대치 | 돌리다 |
범주형으로 변환 | 원핫인코더 |
데이터 맞춤 및 변환 | 적합_변형 |
파이프라인을 만드세요 | make_pipeline |
기본 모델 | |
로지스틱 회귀 | 로지스틱 회귀 |
XGBoost | XGB분류기 |
신경망 | MLP분류자 |
그리드 검색 | 그리드서치CV |
무작위 검색 | 무작위 검색CV |