일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- airflow subdag
- hadoop
- 유튜브 API
- integrated gradient
- session 유지
- TensorFlow
- Counterfactual Explanations
- top_k
- UDF
- gather_nd
- GenericGBQException
- grad-cam
- correlation
- Airflow
- flask
- spark udf
- chatGPT
- 상관관계
- API
- youtube data
- tensorflow text
- login crawling
- BigQuery
- requests
- XAI
- subdag
- Retry
- 공분산
- API Gateway
- GCP
- Today
- Total
데이터과학 삼학년
Ch.5 Categorical Variables: Counting Eggs in theAge of Robotic Chickens 본문
Ch.5 Categorical Variables: Counting Eggs in theAge of Robotic Chickens
Dan-k 2020. 4. 14. 17:28범주형 변수 (Categorical Variables)
-
카테고리나 label을 나타내기 위해 사용되는 변수
-
Ex. 도시 이름, 성별, 요일 등
-
Nonordinal
범주형 변수 인코딩(Encoding Categorical Variables)
-
범주형 변수들의 범주(categories)들은 일반적으로 숫자가 아님
-
숫자가 아닌 범주들을 숫자로 치환시키는 인코딩 기법이 필요
-
가장 단순한 아이디어 : 1~k까지의 숫자로 치환
-
Orderable해져서 안됨
One-Hot Encoding
-
비트의 그룹을 사용
-
변수가 동시에 여러 categories에 속할 수 없을 때 사용
-
e_1+e_2+e_3+...+e_k = 1
Dummy Coding
-
원 핫 인코딩에서 비트 하나를 골라 제거하여 자유도를 하나 줄인 것
Effect Coding
-
더미 코딩에서 기준 범주를 (예제에서 NYC) 0대신 -1로 표현
-
더미 코딩의 Intercept와 Coef를 원 핫 인코딩의 Intercept와 Coef로 바꿔주기 위함
각 범주형 변수 인코딩의 장단점
-
어차피 셋 다 비슷함
-
범주의 수가 많아지면 성능이 떨어짐
-
원 핫 인코딩 : 불필요한 자유도로 인해 동일 문제에 대해 여러 개의 모델 형성
-
더미 코딩 : 각 범주의 효과를 기준 범주를 기준으로 인코딩해 해석이 귀찮음
-
이펙트 코딩 : 모든 값이 -1인 벡터가 dense vector라서 저장과 계산에 비용이 많이 듬
대규모 범주형 변수 처리
-
메모리 효율적이고 학습이 빠르면서 정확한 모델을 만들 수 있는 피처를 찾아야 한다
-
과적합 문제가 생길 수 있음
Feature Hashing
-
Hash function
-
Z -> [1,m]으로 매핑시켜주는 함수
-
입력 크기 > 출력 크기 이기 때문에, 여러 값이 동일한 출력에 매핑됨 : Collision
-
여러 피처들을 하나의 출력값으로 뭉쳐놓기 때문에, 해시처리 된 피처를 해석할 수 없다는 단점이 있음
-
Scikit-learn에 있는 FeatureHasher를 사용해서 구현
Bin counting
-
범주형 변수의 값을 피쳐로 사용하는 대신, 목표 변수에 대한 통계량을 피쳐로 사용한다.
-
ex) 광고 클릭 확률을 계산하기 위해 범주형 변수 ‘사용자 : Alice’ 대신 ‘Alice가 클릭한 확률’을 피쳐로 사용한다는 것.
-
당연한 이야기지만, 기존에 누적된 데이터를 통해 미리 정해진 통계량이 계산되어 있어야한다.
-
사용되는 통계량 : 조건부 확률, 오즈비(odds-ratio), 로그 오즈비 등
-
N+ : 조건부 확률, N- : 1- 조건부 확률, log_N+ : 오즈비
-
용량이 7300031 -> 525697로 크게 줄어들었음.
요약
-
원 핫 인코딩 (n : 데이터 포인트 수, k : 범주 수)
-
공간 요구 : O(n)
-
계산 요구 : O(nk)
-
구현이 쉽고, 정확한 편
-
선형 모델 외에는 비적합
-
범주 수가 크면 비적합
-
피처 해싱 (n : 데이터 포인트 수, m : 해시 저장소 수)
-
공간 요구 : O(n)
-
계산 요구 : O(nm)
-
구현이 쉬움, 새로운 범주, 희귀 범주 처리가 쉬움
-
해시처리된 피처를 해석할 수 없음
-
선형, 커널 모델외에는 비적합
-
정확도에 대해서 아직 검증되지 않음
-
빈 카운팅 (n : 데이터 포인트 수, k : 범주 수, a : 범주에 대해 유지해야하는 통계량들)
-
공간 요구 : O(n+k+a)
-
계산 요구 : 선형 모델에서 O(n)
-
계산 부담이 가장 적음
-
트리 기반 모델에서도 사용 가능 (모든 피처를 반복적으로 검색)
-
새 범주 처리가 쉬움
-
누적된 과거 데이터를 필요로 함
-
업데이트에 지연이 있음
-
누출 가능성에 대한 고려가 필요함
Chapter 5. Categorical Variables: Counting Eggs in the Age of Robotic Chickens¶
import pandas as pd
from sklearn import linear_model
Example 5-1. Linear regression on a categorical variable using one-hot and dummy codes¶
# 연습용 데이터셋 정의
df = pd.DataFrame({'City': ['SF', 'SF', 'SF', 'NYC', 'NYC', 'NYC', 'Seattle', 'Seattle', 'Seattle'],
'Rent': [3999, 4000, 4001, 3499, 3500, 3501, 2499, 2500, 2501]})
df
one_hot_df = pd.get_dummies(df, prefix=['city'])
one_hot_df
lin_reg = linear_model.LinearRegression()
# 원-핫 인코딩 데이터에 대한 선형회귀모델 학습
lin_reg.fit(one_hot_df[['city_NYC', 'city_SF', 'city_Seattle']], one_hot_df['Rent'])
lin_reg.coef_
lin_reg.intercept_
df['Rent'].mean()
# One-hot encoding weights + intercept
w1 = lin_reg.coef_
b1 = lin_reg.intercept_
# 더미 코딩
dummy_df = pd.get_dummies(df, prefix=['city'], drop_first=True)
dummy_df
lin_reg.fit(dummy_df[['city_SF', 'city_Seattle']], dummy_df['Rent'])
lin_reg.coef_
lin_reg.intercept_
# Dummy coding weights + intercept
w2 = lin_reg.coef_
b2 = lin_reg.intercept_
Example 5-2. Linear regression with effect coding¶
effect_df = dummy_df.copy()
effect_df.loc[3:5, ['city_SF', 'city_Seattle']] = -1.0
effect_df
lin_reg.fit(effect_df[['city_SF', 'city_Seattle']], effect_df['Rent'])
lin_reg.coef_
lin_reg.intercept_
# Effect coding weights + intercept
w3 = lin_reg.coef_
b3 = lin_reg.intercept_
# 각 도시별 임대료 비교 플롯
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="whitegrid", font_scale=1.4, color_codes=True)
sns.swarmplot(x="City", y="Rent", data=df);
print('One-hot encoding weights: ' ,w1, '\t and intercept: ', b1)
print('Dummy coding weights: ', w2, '\t\t\t\t and intercept: ', b2)
print('Effect coding weights: ' ,w3, '\t\t and intercept: ', b3)
# geometry of one-hot vs. dummy encoding
# Create a list of values in the best fit line for one-hot encoding
one_hot_y = [((w1[0] * one_hot_df.city_NYC[i]) +
(w1[1] * one_hot_df.city_SF[i]) +
(w1[2] * one_hot_df.city_Seattle[i]) + b1)
for i in range(0,one_hot_df.shape[0])]
# Create a list of values in the best fit line for dummy coding
dummy_y = [((w2[0] * dummy_df.city_SF[i]) +
(w2[1] * dummy_df.city_Seattle[i]) + b2)
for i in range(0,dummy_df.shape[0])]
print(one_hot_y)
print(dummy_y)
Example 5-5. Feature hashing¶
import json
from sklearn.feature_extraction import FeatureHasher
from sys import getsizeof
# 처음 10,000개의 리뷰 로드
f = open('data/yelp/yelp_academic_dataset_review.json', encoding='utf-8')
js = []
for i in range(10000):
js.append(json.loads(f.readline()))
f.close()
review_df = pd.DataFrame(js)
review_df.shape
# 고유한 business_id 개수
m = len(review_df.business_id.unique())
m
h = FeatureHasher(n_features=m, input_type='string')
f = h.transform(review_df['business_id'])
f.shape
review_df['business_id'].unique().tolist()[0:5]
f.toarray()
print('Our pandas Series, in bytes: ', getsizeof(review_df['business_id']))
print('Our hashed numpy array, in bytes: ', getsizeof(f))
Example 5-6. Bin-counting example¶
Click-Through Rate Prediction by Avazu¶
https://www.kaggle.com/c/avazu-ctr-prediction
- train_subset은 전체 6 GB 데이터 중에서 처음 100K 행만 추출한 데이터셋.
df = pd.read_csv('data/ctr/train.csv')
df.shape
df = df.loc[:99999,:]
df.to_csv('data/ctr/train_subset.csv', index=None)
df = pd.read_csv('data/ctr/train_subset.csv')
df.shape
len(df['device_id'].unique())
df.head()
Features are $\theta$ = [$N^+$, $N^-$, $log(N^+)-log(N^-)$, isRest]
$N^+$ = $p(+)$ = $n^+/(n^+ + n^-)$
$N^-$ = $p(-)$ = $n^-/(n^+ + n^-)$
$log(N^+)-log(N^-)$ = $\frac{p(+)}{p(-)}$
isRest = back-off bin (not shown here)
def click_counting(x, bin_column):
clicks = pd.Series(x[x['click'] == 1][bin_column].value_counts(), name='clicks')
no_clicks = pd.Series(x[x['click'] == 0][bin_column].value_counts(), name='no_clicks')
counts = pd.DataFrame([clicks, no_clicks]).T.fillna('0')
counts['total'] = counts['clicks'].astype('int64') + counts['no_clicks'].astype('int64')
return counts
def bin_counting(counts):
counts['N+'] = counts['clicks'].astype('int64').divide(counts['total'].astype('int64'))
counts['N-'] = counts['no_clicks'].astype('int64').divide(counts['total'].astype('int64'))
counts['log_N+'] = counts['N+'].divide(counts['N-'])
# 빈 카운팅 특성만 반환하길 원하면 여기서 필터링 한다.
bin_counts = counts.filter(items= ['N+', 'N-', 'log_N+'])
return counts, bin_counts
# device_id에 대한 빈 카운팅 예제
bin_column = 'device_id'
device_clicks = click_counting(df.filter(items= [bin_column, 'click']), bin_column)
device_all, device_bin_counts = bin_counting(device_clicks)
# 모든 device_id가 포함되었는지 확인
len(device_bin_counts)
device_all.sort_values(by = 'total', ascending=False).head(4)
# 피쳐 크기 비교
print('Our pandas Series, in bytes: ', getsizeof(df.filter(items= ['device_id', 'click'])))
print('Our bin-counting feature, in bytes: ', getsizeof(device_bin_counts))
'Feature Engineering' 카테고리의 다른 글
Ch.7 Nonlinear Featurization viaK-Means Model Stacking (0) | 2020.05.21 |
---|---|
Ch.6 Dimensionality Reduction: Squashing the Data Pancake with PCA (0) | 2020.05.06 |
Ch4. The Effects of Feature Scaling: From Bag-of-Words to Tf-Idf (0) | 2020.04.02 |
Ch3. Text Data: Flattening, Filtering,and Chunking (0) | 2020.03.27 |
Ch2. Fancy Tricks with Simple Numbers (0) | 2020.03.27 |