post-custom-banner
  • ML_1016_01_feature_engineering.ipynb
#먼저 범주형 변수와 수치형 변수를 분리해야한다 
cat_features = features.select_dtypes(include=['object']).columns.to_list()
num_features = features.select_dtypes(exclude='object').columns.to_list()

Impute

6 Different Ways to Compensate for Missing Values In a Dataset

  • 결측치 비율에 따른 범주형 변수 처리 방법(권장)

    • 5~10% : 어떤 방법으로 하든 상관없음
    • 약 15% 정도 : 최빈값 대체
    • 15% 이상 : 결측치 추정 방식 적용
  • Single Imputation

from sklearn.impute import SimpleImputer 

imputer_con = SimpleImputer(strategy="median")
imputer_con.fit(data[con])
# 결측치 확인
df.count()
movie['duration'].isnull().sum()
movie.isnull().sum()

# 결측치 처리
movie.dropna().reset_index(drop=True)            
df.dropna(subset=['tel'], axis=0, inplace=True) #특정 열의 결측치 제거
color=color.fillna('UNK')                       #범주형인경우
duration=duration.fillna(duration.mean())       #수치형인경우
df.fillna(0, inplace=True)  #원본 DataFrame 을 보존할 필요가 없이 바로 결측값을 채워넣기

movie=movie.fillna(movie.median())  
#중앙값이 존재하는 수치형 변수는 채워짐. but 범주형은 그대로 
col={'color':'UNK',
     'director_name':'UNK'}
movie.fillna(col)    #범주형은 dictionary로 지정해서 채우기 
  • Multiveriate Imputation
#다른 피처를 함께 고려하여 대체하는 방법, 수치형만 가능함
from sklearn.experimental import enable_iterative_imputer  # still experimental 
from sklearn.impute import IterativeImputer  #만들어진지 2년밖에 안됨 

data_imp[con] = IterativeImputer(max_iter=10, random_state=0).fit_transform(data[con])
  • 다른 열 기준으로 채우기
df["A"].combine_firest(df["B"])  # A열이 null이라면 B열의 값을 가져와 채운다. 

Outlier Handling

cr=duration.between(60,180)
duration[~cr]=np.nan                 #범위에 속하지 않으면 결측치로 채우기 
duration.fillna(duration.median())   #결측치를 다시 중앙값으로 대체 
#또는 
duration.clip(lower=60, upper=180)   # 60보다 작으면 60, 180보다 크면 180으로 대체 
duration.where(duration<180, 181)    #조건에 만족하지 않으면 181로 대체 

#이상치 처리 
p01 = X_train[num_features].quantile(0.01)
p99 = X_train[num_features].quantile(0.99)

# 1%이하의 값은 1%값으로, 99%이상의 값은 99%값으로 클리핑
X_train[num_features] = X_train[num_features].clip(p01, p99, axis=1)
X_test[num_features] = X_test[num_features].clip(p01, p99, axis=1)

Handling Categorical Variables

  • Tip

    • label encoding : 회귀모델에는 적용하면 안됨, tree 계열 앙상블 모델(rf, XGB, Catboost 등)에는 가능(범주가 많을 경우)
    • 범주값이 너무 많을 경우에는 clustiering 적용 고려
    • Train set에 없는 범주가 Test set에 나타다는 경우, 가장 적은 빈도의 범주값으로 대체해주기
  • One-Hot Encoding

# 학습데이터만 one-hot-encoding할 경우 평가데이터에서만 나타나는 범주값을 처리할 수 없음 (오류발생). 
# => 두 데이터를 합한 후 one-hot-encoding
# 방법 (1)
df_encoded = pd.get_dummies(pd.concat([X_train, X_test]), columns=cat_features)

# 방법 (2)
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
X_oh =encoder.fit_transform(df[cat_features].toarray(),
df_encoded = pd.DataFrame(X_oh, columns = encoder.get_feature_names())
  • Label Encoding
from sklearn.preprocessing import LabelEncoder
data_imp_ohe['state'] = LabelEncoder().fit_transform(data_imp_ohe['state'])

####train, test data 분리 상태인 경우 
encoder = LabelEncoder()
# X_train데이터를 이용 피팅하고 라벨숫자로 변환한다
encoder.fit(train["CATEGORIES"])
train_encoded_cat = encoder.transform(train["CATEGORIES"])

# X_test데이터에만 존재하는 새로 출현한 데이터를 신규 클래스로 추가한다 
for label in np.unique(test["CATEGORIES"]):
    if label not in encoder.classes_: # unseen label 데이터인 경우( )
        encoder.classes_ = np.append(encoder.classes_, label) # 미처리 시 ValueError발생
test_encoded_cat = encoder.transform(test["CATEGORIES"])

train["CATEGORIES"] = pd.DataFrame(train_encoded_cat)
test["CATEGORIES"] = pd.DataFrame(test_encoded_cat)
  • Target Encoding
from category_encoders.target_encoder import TargetEncoder

encoder = TargetEncoder(cols=cat_features)
encoder.fit(te_features[cat_features].iloc[:train_idx, :], y_train)
te_features[cat_features] = encoder.transform(te_features[cat_features])

Handling Numerical Variables

  • 수치형 데이터 구간화를 통한 feature 생성 및 유의미한 feature 확인
    • 이진 분류 문제일 때 유용
df_num = df[num_list]
df_num_des = pd.DataFrame(df_num.describe())

# 수치형 변수 단위에 따라 binning
for i, col in enumerate(num_list):
	bins = [df_num_des.loc['min'][i], df_num_des.loc['25%'][i], df_num_des.loc['75%'][i], np.inf]
    feature_num = col +'_gp'
    df_num[feature_num] = np.digitize(df_num[col], bins)
    
# Lift 계산 
list_of_df =[]
Target_ratio = 0.13   # 원본 데이터의 target(1) 비율 

for i in df_num.columns[:6]:  # 기존 columns
	gp = i +gp
    temp = pd.DataFrame()
    temp['ratio'] = round(df_num.groupby(gp)['isFraud'].mean(), 2)
    temp['lift'] = round(temp['ratio'] / Target_ratio, 2)
    gap = temp['lift'].max() - temp['lift].min()  # gap이 클 수록 target을 구분하는 영향력이 크다고 볼 수 있다. 
    loop_df = pd.DataFrame([[i, gap]], columns=['val', 'gap'])
    list_of_df.append(loop_df)

df_accum_start = pd.concat(list_of_df)
df_accum_start.sort_values(by=['gap'], ascending=False).head(10)
profile
ML/DL swimmer
post-custom-banner

0개의 댓글