<jupyter_start><jupyter_text>- 경진대회: https://www.kaggle.com/c/porto-seguro-safe-driver-prediction- 원본 커널: https://www.kaggle.com/bertcarremans/data-preparation-exploration  - 원본 저자: https://www.kaggle.com/bertcarremans- 참고: https://kaggle-kr.tistory.com/32 (이유한님의 캐글 필사 커리큘럼입니다.)  - 번역: 홍정호(https://blog.naver.com/h0609zxc, KQNG), 번역 오류가 있다면 언제든지 말씀해주세요- 필사 날짜: 2019-07-11훌륭한 커널을 만들어주신 bertcarremans님, 이런 커널들을 정리해주신 이유한님께 감사드립니다.  임의로 가독성을 위해 글의 열, 링크 등은 본문과 조금씩 다릅니다!   번역을 하면서 저도 모르는 부분이 존재하기 때문에 명쾌하지 않은 부분은 찾으면서 보시면 더 좋을것 같습니다.  모두 화이팅입니다!<jupyter_code>from google.colab import drive
drive.mount('/gdrive', force_remount=True)
!ls "/gdrive/My Drive/COLAB/PortoSafeDriverPrediction/"
DATA_PATH = "/gdrive/My Drive/COLAB/PortoSafeDriverPrediction/"<jupyter_output>'Porto Pilsa 1.ipynb'   sample_submission.csv   test.csv   train.csv<jupyter_text>소개 이 노트북은 PorteSeguro 대회의 데이터에 대한 좋은 통찰력을 얻는 것을 목표로합니다.   그 외에도 모델링을위한 데이터 준비를위한 몇 가지 팁과 트릭을 제공합니다. 노트북은 다음과 같은 주요 섹션으로 구성됩니다. - 데이터 시각적 검사- 메타 데이터 정의- 기술 통계- 불균형 클래스 다루기- 데이터의 품질 검사- 탐색 데이터 시각화-피처 엔지니어링- 피처 선택- 피처 스케일링  패키지 로딩<jupyter_code>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import Imputer
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import VarianceThreshold
from sklearn.feature_selection import SelectFromModel
from sklearn.utils import shuffle
from sklearn.ensemble import RandomForestClassifier

pd.set_option("display.max_columns", 100)<jupyter_output><empty_output><jupyter_text>데이터 로딩<jupyter_code>train = pd.read_csv(DATA_PATH + "train.csv")
test = pd.read_csv(DATA_PATH + "test.csv")<jupyter_output><empty_output><jupyter_text>처음 살펴보는 데이터 대회의 데이터 설명을 발췌한 것입니다.- 유사한 피처들은 같은 태그를 가지고 있습니다.(예: ind, reg, car, calc)- 피처 이름 뒤에 bin은 binary 피처를 의미하고, cat은 category 피처를 의미합니다.- 피처 이름에 아무런 접미사가 없는 것은 연속되는 수이거나 서수입니다.- 값이 -1이면 관찰에서 누락된 것을 의미합니다.- 타겟 컬럼은 해당 보험 계약자에 대한 청구가 제기되었는지의 여부입니다. 이것들은 우리가 시작하기 위해 중요한 정보입니다.  이 모든 것을 확인하기 위해 처음과 마지막 부분을 간단히 살펴보겠습니다.<jupyter_code>train.head()
train.tail()<jupyter_output><empty_output><jupyter_text>우리는 다음과 같은 내용을 확인할 수 있다.- 이진 변수- 범주 값이 정수인 범주형 변수- 정수 또는 실수 변수- 값이 -1인 누락된 변수- 타겟 변수와 ID 변수 train 데이터의 행과 열의 수를 살펴보겠습니다.<jupyter_code>train.shape<jupyter_output><empty_output><jupyter_text>59개의 변수와 595,212개의 행이 있습니다. test 데이터에 같은 수의 변수가 있는지 봅시다.  학습할 데이터에 중복 행이 있는지 봅시다.<jupyter_code>train.drop_duplicates()
train.shape<jupyter_output><empty_output><jupyter_text>우선 중복은 없습니다.<jupyter_code>test.shape<jupyter_output><empty_output><jupyter_text>1개의 열이 부족하지만 target 컬럼이므로 정상입니다.  이제 우리가 가지고 있는 각 유형의 변수의 수를 알아봅시다.<jupyter_code>train.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 595212 entries, 0 to 595211
Data columns (total 59 columns):
id                595212 non-null int64
target            595212 non-null int64
ps_ind_01         595212 non-null int64
ps_ind_02_cat     595212 non-null int64
ps_ind_03         595212 non-null int64
ps_ind_04_cat     595212 non-null int64
ps_ind_05_cat     595212 non-null int64
ps_ind_06_bin     595212 non-null int64
ps_ind_07_bin     595212 non-null int64
ps_ind_08_bin     595212 non-null int64
ps_ind_09_bin     595212 non-null int64
ps_ind_10_bin     595212 non-null int64
ps_ind_11_bin     595212 non-null int64
ps_ind_12_bin     595212 non-null int64
ps_ind_13_bin     595212 non-null int64
ps_ind_14         595212 non-null int64
ps_ind_15         595212 non-null int64
ps_ind_16_bin     595212 non-null int64
ps_ind_17_bin     595212 non-null int64
ps_ind_18_bin     595212 non-null int64
ps_reg_01         595212 non-null float64
ps_reg_02         595212 non-null float64
ps_re[...]<jupyter_text>info() 메서드를 사용하여 데이터 유형이 정수형 또는 실수형임을 알 수 있습니다.  데이터 세트에 Null 값이 없는데 누락된 값이 -1로 대체된 것이기 때문에 그렇습니다. 이 부분은 나중에 살펴보겠습니다.  메타 데이터 데이터 관리를 쉽게 하기 위해 변수에 대한 메타 정보를 데이터프레임에 저장합니다.  이렇게 하면 분석, 시각화, 모델링을 위해 특정 변수를 선택하고자 할 때 도움이 될 것입니다. 이런 방식으로 저장할 것입니다.- role: input, ID, target- level: nominal, interval, ordinal, binary- keep: True or False- dtype: int, float, str<jupyter_code>data = []
for f in train.columns:
    # role 정의
    if f == 'target':
        role = 'target'
    elif f == 'id':
        role = 'id'
    else:
        role = 'input'
         
    # level 정의
    if 'bin' in f or f == 'target':
        level = 'binary'
    elif 'cat' in f or f == 'id':
        level = 'nominal'
    elif train[f].dtype == float:
        level = 'interval'
    elif train[f].dtype == int:
        level = 'ordinal'
        
    # id를 제외한 모든 변수를 True로 초기화
    keep = True
    if f == 'id':
        keep = False
    
    # 데이터 유형 정의
    dtype = train[f].dtype
    
    # 변수에 대한 메타 데이터를 담는 사전 만들기
    f_dict = {
        'varname': f,
        'role': role,
        'level': level,
        'keep': keep,
        'dtype': dtype
    }
    data.append(f_dict)
    
meta = pd.DataFrame(data, columns=['varname', 'role', 'level', 'keep', 'dtype'])
meta.set_index('varname', inplace=True)
meta<jupyter_output><empty_output><jupyter_text>드롭되지 않은 모든 nominal 변수를 추출하는 예제입니다.<jupyter_code>meta[(meta.level == 'nominal') & (meta.keep)].index<jupyter_output><empty_output><jupyter_text>role 및 level 당 변수의 개수를 출력합니다<jupyter_code>pd.DataFrame({'count' : meta.groupby(['role', 'level'])['role'].size()}).reset_index()<jupyter_output><empty_output><jupyter_text>기술 통계(Descriptive statistics) 데이터 프레임에 describe 메소드를 적용 할 수도 있습니다.  그러나 범주형 변수와 id 변수에서 평균, 표준 등을 계산하는 것은별로 의미가 없습니다.  범주형 변수는 나중에 시각적으로 살펴볼 것입니다. 메타 파일 덕분에 기술 통계를 계산할 변수를 쉽게 선택할 수 있습니다.  일을 분명히하기 위해 우리는 데이터 유형마다 이것을 할 것입니다.    Interval 변수<jupyter_code>v = meta[(meta.level == 'interval') & (meta.keep)].index
train[v].describe()<jupyter_output><empty_output><jupyter_text>reg 변수- ps_reg_03 변수만 누락 값이 존재- 변수들 마다 범위(최소-최대)는 다릅니다. 스케일링을 할 수 있지만 우리가 사용하려는 분류기마다 다를 것 입니다.  car 변수- ps_car_12 와 ps_car_15는 누락 값이 존재- 변수들 마다 범위가 다르고 스케일링 할 수 있다.  calc 변수- 누락값이 없다- 최대가 0.9인 어떤 비율일 것이다.- 3개의 calc 변수는 모두 유사한 분포를 가지고 있다.  Ordinal 변수<jupyter_code>v = meta[(meta.level == "ordinal") & (meta.keep)].index
train[v].describe()<jupyter_output><empty_output><jupyter_text>- ps_car_11만 유일하게 누락값이 존재- 다양한 범위를 다루기 위해 스케일링을 적용 할 수 있습니다  Binary 변수<jupyter_code>v = meta[(meta.level == "binary") & (meta.keep)].index
train[v].describe()<jupyter_output><empty_output><jupyter_text>- train 데이터의 선험은 3.645 %로 매우 불균형합니다.(A priori in the train data is 3.645%, which is strongly imbalanced.)- 평균을 통해 우리는 대부분의 경우 값이 0이라고 말할 수 있습니다.  불균형 클래스 다루기 target = 1 인 레코드의 비율은 target = 0보다 훨씬 적습니다.  이것은 정확도가 높지만 실제로 부가 가치가있는 모델인지는 모릅니다.이 문제를 해결할 수있는 두 가지 전략은 다음과 같습니다.  - target=1 레코드를 오버샘플링- target=0 레코드를 언더샘플링 물론 더 많은 전략이 있으며 MachineLearningMastery.com은 멋진 개요를 제공합니다.   (링크를 제공하려 했으나 제가 열어보니 없는 링크입니다.)  우리는 오히려 커다란 훈련 세트가 있으므로 언더 샘플링을 할 수 있습니다.<jupyter_code>desired_apriori=0.10

# target 값에 따라 인덱스를 가져옵니다.
idx_0 = train[train.target == 0].index
idx_1 = train[train.target == 1].index

# target 값에 따라 레코드의 원래 번호를 가져옵니다.
nb_0 = len(train.loc[idx_0])
nb_1 = len(train.loc[idx_1])

# 언더샘플링 비율과 target이 0인 레코드 수를 계산합니다.
undersampling_rate = ((1-desired_apriori)*nb_1)/(nb_0*desired_apriori)
undersampled_nb_0 = int(undersampling_rate*nb_0)
print('Rate to undersample records with target=0: {}'.format(undersampling_rate))
print('Number of records with target=0 after undersampling: {}'.format(undersampled_nb_0))

# target이 0인 레코드를 무작위로 선택하여  언더샘플된 인덱스를 구합니다.
undersampled_idx = shuffle(idx_0, random_state=37, n_samples=undersampled_nb_0)

# target이 1인 인덱스와 언더샘플된 인덱스를 합쳐 구성합니다.
idx_list = list(undersampled_idx) + list(idx_1)

# 언더샘플링 데이터프레임을 반환합니다.
train = train.loc[idx_list].reset_index(drop=True)
## 확인해보기 위해 제가 추가한 짧은 코드입니다.
print(train.shape)
train["target"].value_counts()<jupyter_output>(216940, 59)<jupyter_text>데이터 품질 검사  누락된 값 검사 누락은 -1로 표시됩니다.<jupyter_code>vars_with_missing = []

for f in train.columns:
  missings = train[train[f] == -1][f].count()
  if missings > 0:
    vars_with_missing.append(f)
    missings_perc = missings / train.shape[0]
    
    print('Variable {} has {} records ({:.2%}) with missing values'.format(f, missings, missings_perc))
print('In total, there are {} variables with missing values'.format(len(vars_with_missing)))<jupyter_output>Variable ps_ind_02_cat has 103 records (0.05%) with missing values
Variable ps_ind_04_cat has 51 records (0.02%) with missing values
Variable ps_ind_05_cat has 2256 records (1.04%) with missing values
Variable ps_reg_03 has 38580 records (17.78%) with missing values
Variable ps_car_01_cat has 62 records (0.03%) with missing values
Variable ps_car_02_cat has 2 records (0.00%) with missing values
Variable ps_car_03_cat has 148367 records (68.39%) with missing values
Variable ps_car_05_cat has 96026 records (44.26%) with missing values
Variable ps_car_07_cat has 4431 records (2.04%) with missing values
Variable ps_car_09_cat has 230 records (0.11%) with missing values
Variable ps_car_11 has 1 records (0.00%) with missing values
Variable ps_car_14 has 15726 records (7.25%) with missing values
In total, there are 12 variables with missing values<jupyter_text>- ps_car_03_cat, ps_car_05_cat: 누락 값의 비율이 너무 높습니다. 제거하세요.- 누락 된 값이있는 다른 범주형 변수의 경우 누락 값 -1을 그대로 둘 수 있습니다.- ps_reg_03 (continuous): 모든 레코드의 18 %에 대해 값이 누락되었습니다. 평균값으로 바꾸십시오.- ps_car_11 (ordinal): 누락 된 값이있는 레코드가 5 개뿐입니다. 모드로 교체하십시오.- ps_car_12 (continuous) : 누락 된 값이있는 레코드가 1 개뿐입니다. 평균값으로 교체하십시오.- ps_car_14 (continuous) : 모든 레코드의 7 %에 대해 값이 누락되었습니다. 평균값으로 바꾸십시오.<jupyter_code># 누락 된 값이 너무 많은 변수는 제거
vars_to_drop = ['ps_car_03_cat', 'ps_car_05_cat']
train.drop(vars_to_drop, inplace=True, axis=1)
meta.loc[(vars_to_drop),'keep'] = False  # 메타 데이터 갱신

# 평균 또는 모드로 대체하기
mean_imp = Imputer(missing_values=-1, strategy='mean', axis=0)
mode_imp = Imputer(missing_values=-1, strategy='most_frequent', axis=0)
train['ps_reg_03'] = mean_imp.fit_transform(train[['ps_reg_03']]).ravel()
train['ps_car_12'] = mean_imp.fit_transform(train[['ps_car_12']]).ravel()
train['ps_car_14'] = mean_imp.fit_transform(train[['ps_car_14']]).ravel()
train['ps_car_11'] = mode_imp.fit_transform(train[['ps_car_11']]).ravel()<jupyter_output>/usr/local/lib/python3.6/dist-packages/sklearn/utils/deprecation.py:66: DeprecationWarning: Class Imputer is deprecated; Imputer was deprecated in version 0.20 and will be removed in 0.22. Import impute.SimpleImputer from sklearn instead.
  warnings.warn(msg, category=DeprecationWarning)
/usr/local/lib/python3.6/dist-packages/sklearn/utils/deprecation.py:66: DeprecationWarning: Class Imputer is deprecated; Imputer was deprecated in version 0.20 and will be removed in 0.22. Import impute.SimpleImputer from sklearn instead.
  warnings.warn(msg, category=DeprecationWarning)<jupyter_text>범주형 변수의 카디널리티 확인하기 카디널리티는 변수의 존재하는 다른 값들의 수를 의미합니다.  나중에 범주형 변수에서 더미 변수를 만들므로 많은 다른 값을 갖는 변수가 있는지 확인해야합니다.  우리는 이것을 더미 변수로 취급하는 것과 다르게 처리해야합니다.<jupyter_code>v = meta[(meta.level == 'nominal') & (meta.keep)].index

for f in v:
    dist_values = train[f].value_counts().shape[0]
    print('Variable {} has {} distinct values'.format(f, dist_values))<jupyter_output>Variable ps_ind_02_cat has 5 distinct values
Variable ps_ind_04_cat has 3 distinct values
Variable ps_ind_05_cat has 8 distinct values
Variable ps_car_01_cat has 13 distinct values
Variable ps_car_02_cat has 3 distinct values
Variable ps_car_04_cat has 10 distinct values
Variable ps_car_06_cat has 18 distinct values
Variable ps_car_07_cat has 3 distinct values
Variable ps_car_08_cat has 2 distinct values
Variable ps_car_09_cat has 6 distinct values
Variable ps_car_10_cat has 3 distinct values
Variable ps_car_11_cat has 104 distinct values<jupyter_text>ps_car_11_cat만 많은 다른 값을 가지고 있습니다.  **EDIT**  nickycan은 내 첫 번째 솔루션이 데이터 누설이 있을 수 있다라는 훌륭한 지적을 해주었고,   같은 내용을 다루는 oliver가 만든 커널을  나에게 알려주었다.  그로므로 나는 이 부분을 oliver의 커널로 대체하였다. 모든 크레딧(공?)은 그의 것이다.  이것은 캐글 대회에 참여함으로써 당신이 배울 수 있는 훌륭한 것이다.nickycan 캐글 프로필: https://www.kaggle.com/nickycan  oliver 캐글 프로필: https://www.kaggle.com/ogrellier<jupyter_code># Script by https://www.kaggle.com/ogrellier
# Code: https://www.kaggle.com/ogrellier/python-target-encoding-for-categorical-features
def add_noise(series, noise_level):
    return series * (1 + noise_level * np.random.randn(len(series)))

def target_encode(trn_series=None, 
                  tst_series=None, 
                  target=None, 
                  min_samples_leaf=1, 
                  smoothing=1,
                  noise_level=0):
    """
    Smoothing은 <NAME>의 논문에서와 같이 계산됩니다.
    https://kaggle2.blob.core.windows.net/forum-message-attachments/225952/7441/high%20cardinality%20categoricals.pdf
    trn_series : pd.Series 형태의 학습할 범주형 피처
    tst_series : pd.Series 형태의 테스트할 범주형 피처
    target : pd.Series 형태의 타겟 데이터
    min_samples_leaf (int) : 범주의 평균을 고려할 최소 샘플
    smoothing (int) : 범주 평균과 이전의 균형을 맞추기 위한 스무딩 효과 
    """ 
    assert len(trn_series) == len(target)
    assert trn_series.name == tst_series.name
    temp = pd.concat([trn_series, target], axis=1)
    # 타겟 평균을 계산
    averages = temp.groupby(by=trn_series.name)[target.name].agg(["mean", "count"])
    # 스무딩 계산
    smoothing = 1 / (1 + np.exp(-(averages["count"] - min_samples_leaf) / smoothing))
    # 모든 타겟 데이터에 평균 적용하기
    prior = target.mean()
    # 카운트가 클수록 full_avg가 적어집니다.
    averages[target.name] = prior * (1 - smoothing) + averages["mean"] * smoothing
    averages.drop(["mean", "count"], axis=1, inplace=True)
    # 학습, 테스트 데이터에 평균 적용
    ft_trn_series = pd.merge(
        trn_series.to_frame(trn_series.name),
        averages.reset_index().rename(columns={'index': target.name, target.name: 'average'}),
        on=trn_series.name,
        how='left')['average'].rename(trn_series.name + '_mean').fillna(prior)
    # pd.merge는 인덱스를 유지하지 않으므로 복원합니다.
    ft_trn_series.index = trn_series.index 
    ft_tst_series = pd.merge(
        tst_series.to_frame(tst_series.name),
        averages.reset_index().rename(columns={'index': target.name, target.name: 'average'}),
        on=tst_series.name,
        how='left')['average'].rename(trn_series.name + '_mean').fillna(prior)
    # pd.merge는 인덱스를 유지하지 않으므로 복원합니다.
    ft_tst_series.index = tst_series.index
    return add_noise(ft_trn_series, noise_level), add_noise(ft_tst_series, noise_level)
train_encoded, test_encoded = target_encode(train["ps_car_11_cat"], 
                             test["ps_car_11_cat"], 
                             target=train.target, 
                             min_samples_leaf=100,
                             smoothing=10,
                             noise_level=0.01)
    
train['ps_car_11_cat_te'] = train_encoded
train.drop('ps_car_11_cat', axis=1, inplace=True)
meta.loc['ps_car_11_cat','keep'] = False  # Updating the meta
test['ps_car_11_cat_te'] = test_encoded
test.drop('ps_car_11_cat', axis=1, inplace=True)<jupyter_output><empty_output><jupyter_text>탐색 데이터 시각화  범주형 변수 타겟 변수가 1 인 고객의 범주형 변수와 비율을 살펴 보겠습니다.<jupyter_code>v = meta[(meta.level == 'nominal') & (meta.keep)].index

for f in v:
    plt.figure()
    fig, ax = plt.subplots(figsize=(20,10))
    # 범주형 값 당 타겟값이 1인 퍼센트를 계산
    cat_perc = train[[f, 'target']].groupby([f],as_index=False).mean()
    cat_perc.sort_values(by='target', ascending=False, inplace=True)
    # Bar 플롯
    # 타겟 평균으로 내림차순
    sns.barplot(ax=ax, x=f, y='target', data=cat_perc, order=cat_perc[f])
    plt.ylabel('% target', fontsize=18)
    plt.xlabel(f, fontsize=18)
    plt.tick_params(axis='both', which='major', labelsize=18)
    plt.show();<jupyter_output><empty_output><jupyter_text>누락된 값이 있는 변수에서 알 수 있듯, 모드를 사용하는 것 대신 누락된 값을 별도의 범주 값으로 유지하는 것은 좋은 생각이다.  누락된 값을 나타내는 고객들은 보험금 청구를 요구할 확률이 훨씬 더 높은 것으로 보인다.  Interval 변수 Interval 변수 사이의 상관 관계를 확인해봅니다.  히트맵은 변수간의 상관 관계를 시각화하는 좋은 방법입니다.  아래 코드는 Michael Waskom의 예제를 기반으로합니다.<jupyter_code>def corr_heatmap(v):
    correlations = train[v].corr()

    # 두 가지 색상 사이의 색상 맵 만들기
    cmap = sns.diverging_palette(220, 10, as_cmap=True)

    fig, ax = plt.subplots(figsize=(10,10))
    sns.heatmap(correlations, cmap=cmap, vmax=1.0, center=0, fmt='.2f',
                square=True, linewidths=.5, annot=True, cbar_kws={"shrink": .75})
    plt.show();
    
v = meta[(meta.level == 'interval') & (meta.keep)].index
corr_heatmap(v)<jupyter_output><empty_output><jupyter_text>다음 변수 사이에는 강한 상관 관계가 존재합니다. - ps_reg_02 and ps_reg_03 (0.70)- ps_car_12 and ps_car13 (0.67)- ps_car_12 and ps_car14 (0.58)- ps_car_13 and ps_car15 (0.67) seaborn은 변수 사이의 (선형) 관계를 시각화하는 몇 가지 편리한 플롯을 가지고 있습니다.  변수 사이의 관계를 시각화하기 위해 pair플롯을 사용할 수 있습니다.  히트 맵은 이미 제한된 수의 상관 관계 변수를 보여주기 때문에 각 상관 관계가 높은 변수를 개별적으로 살펴볼 것입니다.   **NOTE:**프로세스의 속도를 높이기 위해 train 데이터의 샘플을 가져옵니다.<jupyter_code>s = train.sample(frac=0.1)<jupyter_output><empty_output><jupyter_text>ps_reg_02 and ps_reg_03 회귀선이 보여 주듯이이 변수들 사이에는 선형 관계가 있습니다.  hue 변수 덕분에 target = 0 및 target = 1에 대한 회귀선이 동일하다는 것을 알 수 있습니다.<jupyter_code>sns.lmplot(x='ps_reg_02', y='ps_reg_03', data=s, hue='target', palette='Set1', scatter_kws={'alpha':0.3})
plt.show()<jupyter_output><empty_output><jupyter_text>ps_car_12 and ps_car_13<jupyter_code>sns.lmplot(x='ps_car_12', y='ps_car_13', data=s, hue='target', palette='Set1', scatter_kws={'alpha':0.3})
plt.show()<jupyter_output><empty_output><jupyter_text>ps_car_12 and ps_car_14<jupyter_code>sns.lmplot(x='ps_car_12', y='ps_car_14', data=s, hue='target', palette='Set1', scatter_kws={'alpha':0.3})
plt.show()<jupyter_output><empty_output><jupyter_text>ps_car_13 and ps_car_15<jupyter_code>sns.lmplot(x='ps_car_15', y='ps_car_13', data=s, hue='target', palette='Set1', scatter_kws={'alpha':0.3})
plt.show()<jupyter_output><empty_output><jupyter_text>어떤 상관 관계가 있는 변수를 유지할 것인지 어떻게 정해야 할까?  변수에 대한 주성분 분석(PCA)을 수행하여 차원을 줄일 수 있다.  그러나 상관 관계 변수의 수가 다소 적기 때문에, 우리는 모델이 무거워지게 할 것입니다.참고할 PCA 커널: https://www.kaggle.com/bertcarremans/reducing-number-of-numerical-features-with-pca  ordinal 변수 간의 상관 관계 확인<jupyter_code>v = meta[(meta.level == 'ordinal') & (meta.keep)].index
corr_heatmap(v)<jupyter_output><empty_output><jupyter_text>ordinal 변수에 대해서는 많은 상관 관계를 볼 수 없습니다.  반면에 타겟 값을 기준으로 그룹화 할 때 분포가 어떻게되는지 살펴볼 수 있습니다.    피처 엔지니어링  **더미 변수 만들기** 범주형 변수의 값은 순서 또는 크기를 나타내지 않는다.    예를 들어 카테고리 2는 카테고리 1의 값의 2배가 아니다.  그러므로 우리는 카테고리 값을 다루기 위해 더미 변수를 만들 수 있습니다.  첫 번째 더미 변수는 원래 변수의 범주에 대해 생성 된 다른 더미 변수에서 파생 될 수 있기 때문에 버립니다.<jupyter_code>v = meta[(meta.level == 'nominal') & (meta.keep)].index
print('Before dummification we have {} variables in train'.format(train.shape[1]))
train = pd.get_dummies(train, columns=v, drop_first=True)
print('After dummification we have {} variables in train'.format(train.shape[1]))<jupyter_output>Before dummification we have 57 variables in train
After dummification we have 109 variables in train<jupyter_text>더미 변수를 만들면 train 세트에 52개의 변수가 추가됩니다.  interaction 변수 만들기<jupyter_code>v = meta[(meta.level == 'interval') & (meta.keep)].index
poly = PolynomialFeatures(degree=2, interaction_only=False, include_bias=False)
interactions = pd.DataFrame(data=poly.fit_transform(train[v]), columns=poly.get_feature_names(v))
interactions.drop(v, axis=1, inplace=True)  # 원래의 컬럼 제거
# train 데이터에 상호 작용 변수 연결
print('Before creating interactions we have {} variables in train'.format(train.shape[1]))
train = pd.concat([train, interactions], axis=1)
print('After creating interactions we have {} variables in train'.format(train.shape[1]))<jupyter_output>Before creating interactions we have 109 variables in train
After creating interactions we have 164 variables in train<jupyter_text>train 데이터에 추가적인 상호 작용 변수를 넣어줍니다.  get_feature_names 메소드 덕분에이 새로운 변수에 열 이름을 할당 할 수 있습니다.<jupyter_code>train.head()<jupyter_output><empty_output><jupyter_text>피처 선택  분산이 낮거나 0인 피처 제거 개인적으로는 분류 알고리즘이 유지할 피처를 고르는 것을 선호합니다.   그러나 우리가 할 수있는 한가지 일이 있습니다.  그것은 변화가 없거나 매우 적은 피처들을 제거하는 것입니다.   Sklearn은이를위한 편리한 방법을 가지고 있습니다 : VarianceThreshold.  기본적으로 분산이 0인  피처를 제거합니다.  이전 단계에서 분산이 0인 피처가 없다는것을 알았으므로 이 대회에 적용하진 않을 것입니다.  그러나 1% 미만의 분산을 가진 피처를 제거하면 31 개의 변수가 제거됩니다.<jupyter_code>selector = VarianceThreshold(threshold=.01)
selector.fit(train.drop(['id', 'target'], axis=1)) # id와 target 변수 없이 훈련하는 것이 적합하다.
f = np.vectorize(lambda x : not x) # 부울 배열 요소를 토글하는 함수
v = train.drop(['id', 'target'], axis=1).columns[f(selector.get_support())]
print('{} variables have too low variance.'.format(len(v)))
print('These variables are {}'.format(list(v)))<jupyter_output>28 variables have too low variance.
These variables are ['ps_ind_10_bin', 'ps_ind_11_bin', 'ps_ind_12_bin', 'ps_ind_13_bin', 'ps_car_12', 'ps_car_14', 'ps_car_11_cat_te', 'ps_ind_05_cat_2', 'ps_ind_05_cat_5', 'ps_car_01_cat_1', 'ps_car_01_cat_2', 'ps_car_04_cat_3', 'ps_car_04_cat_4', 'ps_car_04_cat_5', 'ps_car_04_cat_6', 'ps_car_04_cat_7', 'ps_car_06_cat_2', 'ps_car_06_cat_5', 'ps_car_06_cat_8', 'ps_car_06_cat_12', 'ps_car_06_cat_16', 'ps_car_06_cat_17', 'ps_car_09_cat_4', 'ps_car_10_cat_1', 'ps_car_10_cat_2', 'ps_car_12^2', 'ps_car_12 ps_car_14', 'ps_car_14^2']<jupyter_text>우리는 분산을 기반으로 선택한다면 오히려 많은 변수를 잃을 것입니다.  그러나 우리는 변수가 많지 않으므로 분류기가 선택하도록 할 것입니다.  변수가 더 많은 데이터 세트의 경우 처리 시간이 줄어들 수 있습니다.     Sklearn은 다른 피처 선택 방법도 제공합니다.    이러한 메소드 중 하나는 SelectFromModel이며 다른 분류기가 최상의 피처를  선택하고 그것을 이어나갈 수 있습니다.  아래에서는 랜덤 포레스트 (Random Forest)로 어떻게하는지 보여 드리겠습니다.sklearn의 Feature selection: https://scikit-learn.org/stable/modules/feature_selection.html    Selecting features with a Random Forest and SelectFromModel 우리는 랜덤 포레스트의 중요한 피처들을 기반으로 피처 선택을 할 것입니다.  Sklearn의 SelectFromModel을 사용하여 지킬 변수 수를 지정할 수 있습니다.  피처 중요도 수준에서 임계 값을 수동으로 설정할 수 있습니다.  하지만 우리는 간단히 상위 50 % 상위 변수만 선택할 것입니다. 아래 셀의 코드는 <NAME>의 GitHub 레포에서 빌려 왔습니다.  이 repo에는 자신의 책 Python Machine Learning의 코드 샘플이 포함되어 있으며 반드시 읽어야합니다.  <NAME>의 GitHub : https://github.com/rasbt/python-machine-learning-book/blob/master/code/ch04/ch04.ipynb<jupyter_code>X_train = train.drop(['id', 'target'], axis=1)
y_train = train['target']

feat_labels = X_train.columns

rf = RandomForestClassifier(n_estimators=1000, random_state=0, n_jobs=-1)

rf.fit(X_train, y_train)
importances = rf.feature_importances_

indices = np.argsort(rf.feature_importances_)[::-1]

for f in range(X_train.shape[1]):
    print("%2d) %-*s %f" % (f + 1, 30,feat_labels[indices[f]], importances[indices[f]]))<jupyter_output>1) ps_car_11_cat_te               0.021241
 2) ps_car_13                      0.017428
 3) ps_car_12 ps_car_13            0.017303
 4) ps_car_13^2                    0.017241
 5) ps_reg_03 ps_car_13            0.017170
 6) ps_car_13 ps_car_14            0.017121
 7) ps_car_13 ps_car_15            0.016738
 8) ps_reg_01 ps_car_13            0.016703
 9) ps_reg_03 ps_car_14            0.016207
10) ps_reg_03 ps_car_12            0.015530
11) ps_reg_03 ps_car_15            0.015206
12) ps_car_14 ps_car_15            0.015011
13) ps_reg_01 ps_reg_03            0.014737
14) ps_car_13 ps_calc_01           0.014734
15) ps_car_13 ps_calc_03           0.014713
16) ps_reg_02 ps_car_13            0.014678
17) ps_car_13 ps_calc_02           0.014639
18) ps_reg_01 ps_car_14            0.014360
19) ps_reg_03                      0.014265
20) ps_reg_03^2                    0.014242
21) ps_reg_03 ps_calc_03           0.013815
22) ps_reg_03 ps_calc_02           0.013801
23) ps_reg_03 ps_calc_01        [...]<jupyter_text>SelectFromModel을 사용하여 사용할 사전 분류기와 피처 중요도를 위한 임계값을 명시할 수 있다.    get_support 메소드를 사용하면 train 데이터의 변수 수를 제한 할 수 있습니다.<jupyter_code>sfm = SelectFromModel(rf, threshold='median', prefit=True)
print('Number of features before selection: {}'.format(X_train.shape[1]))
n_features = sfm.transform(X_train).shape[1]
print('Number of features after selection: {}'.format(n_features))
selected_vars = list(feat_labels[sfm.get_support()])
train = train[selected_vars + ['target']]<jupyter_output><empty_output><jupyter_text>피처 스케일링 앞서 언급했듯이 Standard 스케일링을 train 데이터에 적용 할 수 있습니다.  몇몇 분류기는 이 작업을 하면 더 좋은 성능을 보입니다.<jupyter_code>scaler = StandardScaler()
scaler.fit_transform(train.drop(['target'], axis=1))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10910696266397578, 'fraction_numerical': 0.0463757147662294, 'mean_word_length': 4.077924850555081, 'pattern_counts': {'":': 1, '<': 131, '<?xml version=': 0, '>': 132, 'https://': 13, 'lorem ipsum': 0, 'www.': 8, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '34', 'dir': 'jupyter-structured-clean-dedup', 'id': '360468', 'license': 'MIT', 'n_tokens_mistral': 13046, 'n_tokens_neox': 14393, 'n_words': 2504, 'path': 'ml/porto_driver_insurance/Porto_Pilsa_1.ipynb', 'repo_name': 'groovallstar/test2', 'size': '23821'}