❓ 범주가 적은 값을 피처로 만들어주면 생기는 문제
❗ 과대적합
❓ 너무 희소한 값이라면 one-hot-encoding할 때 어떤 전처리를 할 수 있을까?
❗ ordinal과 one-ho encoding으로 이산화, '기타' 등으로 data binning, 결측치로 처리
❓ 표준 정규분포 형태로 만들기 위해서는 스케일링 VS 로그변환 중 어떤게 먼저일까?
❗ 로그변환
❓ 왜 데이터를 정규분포 형태로 만들어주면 머신러닝이나 딥러닝에서 더 나은 성능을 낼까?
❗ 너무 한쪽에 몰려있거나 치우쳐져 있을 때보다 고르게 분포되어 있으면 데이터의 특성을 더 고르게 학습할 수 있음
❓ 음수인 값이 너무 뾰족하거나 치우쳐져 있어서 로그를 취하기 위해서는 어떻게 전처리를 해야 할까?
❗ 모든 값이 양수고 1보다 작은 값이 있을 때는 1을 더함
❓-1️⃣ 너무 큰 음수값이 있을 때, 예를 들어 -1000이라면??
❗-1️⃣ 최솟값이 1이 되게 더해주면 됨 ex) 1001을 더해줌
❓ -1000에서 1001을 더해서 로그변환을 해준 후 원래 값으로 다시 복원하려면 어떻게 해야 할까?
❗ 지수 함수로 변환하고 -1001
ex) np.exp(x) -1001
✅cut, qcut:
-이 방법은 RFM 기법에서도 종종 사용되는 방법으로 비즈니스 분석에서 다룰 예정
-Recency, Frequency, Monetary => 고객이 얼마나 최근에, 자주, 많이 구매했는지를 분석할 때 사용
-연속된 수치 데이터를 군간화 하면 머신러닝 알고리즘에 힌트를 줄 수 있음
-트리모델이라면 너무 잘게 데이터를 나누지 않아 일반화 하는데 도움이 될 수 있음
-> 데이터를 나누는 기준이 중요한데 EDA를 통해 어떻게 나누는 것이 예측에 도움이 될지 확인
-> 연속된 수치데이터를 나누는 기준에 따라 모델의 성능에 영향을 줌
-> 오히려 잘못 나누면 모델의 성능이 떨어질 수 있음!!
❓ LabelEncoder, OrdinalEncoder 의 입력값의 차이?
❗ Ordinal Encoding은 Label Encoding과 달리 변수에 순서를 고려한다는 점에서 큰 차이를 가짐. Label Encoding이 알파벳 순서 혹은 데이터셋에 등장하는 순서대로 매핑하는 것과 달리 Oridnal Encoding은 Label 변수의 순서 정보를 사용자가 지정해서 담을 수 있음.
-> LabelEncoder 입력이 1차원 y 값, OrdinalEncoder 입력이 2차원 X값
🔷 X => 독립변수, 시험의 문제, 2차원 array 형태, 학습할 피처
y => label, target, 정답, 시험의 답안, 1차원 벡터
✒️ X는 보통 2차원으로 대문자로 표기하고 y는 소문자로 표기하는것이 꼭 그렇게 써야된다는 아니지만 관례처럼 사용
feature_names : 학습(훈련), 예측에 사용할 컬럼을 리스트 형태로 만들어서 변수에 담아줍니다.
label_name : 정답값
X_train : feature_names 에 해당되는 컬럼만 train에서 가져옵니다.
학습(훈련)에 사용할 데이터셋 예) 시험의 기출문제
X_test : feature_names 에 해당되는 컬럼만 test에서 가져옵니다.
예측에 사용할 데이터셋 예) 실전 시험문제
y_train : label_name 에 해당 되는 컬럼만 train에서 가져옵니다.
학습(훈련)에 사용할 정답 값 예) 기출문제의 정답
-> 공식문서 용어
Q. 인코더 3가지의 공통점
A. 범주형 데이터 -> 수치형 데이터
train_ohe = ohe.fit_transform(train[["MSZoning", "Neighborhood"]]).toarray()
test_ohe= ohe.transform(test[["MSZoning", "Neighborhood"]])
pd.DataFrame(train_ohe, columns=ohe.get_feature_names_out())
-> 오류나는 코드
`ohe = OneHotEncoder(handle_unknown = 'ignore')`
-> 수정 코드
❓ 구분이 잘 안 되는 값에 대해 power transform 을 해주기도 하는데 반대로 너무 차이가 많이 나는 값을 줄일 때 사용할 수 있는 방법은?
❗ 꼭 정답이 있다기 보다는 EDA를 해보고 어떤 스케일링을 하면 머신러닝 모델이 값을 학습하는데 도움이 될지 고민해보면 좋음
✒️ root, log transform 도 해볼 수 있지만 변환이 정답은 아님. 성능이 올라가고 안 올라가고는 EDA 등을 통해 확인해 보고 왜 점수가 오르고 내리는지 확인해 보는 습관을 길러보세요.
for col in train.select_dtypes(include="O").columns: col_count = train[col].value_counts(1)*100 if col_count[0] > 90: print(col)
-> 치우친 값은 드롭하거나 처리해주면 좋음
결측치 수와 비율을 함께 보고 싶다면 합계와 비율을 구해서 concat으로 합친다
concat 에서 axis=0 은 행, axis=1은 열을 의미
메서드체이닝을 할 때는 도움말 보기가 잘 동작하지 않기 때문에 도움말을 보기 위해서는 변수에 할당하고 사용하는 것도 좋다.
결측비율이 높은 값들을 제거
isna_mean[isna_mean > 0.8].index
df = df.drop(null_feature, axis=1)
어떤 피처가 삭제되었는지 확인하기 확인
set(test.columns) - set(train.columns)
수치형 변수를 모두 중앙값으로 대체
수치형 변수를 대체할 때는 원래의 값이 너무 왜곡되지 않는지도 주의
중앙값 외에도 평균값 등의 대표값을 대체할 수 있음
df[feature_num] = df[feature_num].fillna(df[feature_num].median())
df.corr()['SalePrice'][abs(df.corr()["SalePrice"])>0.5]
df.corr()['SalePrice'][abs(df.corr()["SalePrice"])>0.5].index
df['TotalSF'] = df['TotalBsmtSF'] + df['1stFlrSF'] + df['2ndFlrSF']
fill_mode = ['MSZoning', 'KitchenQual', 'Exterior1st', 'Exterior2nd', 'SaleType', 'Functional'] df[fill_mode] = df[fill_median].fillna('mode')
수치 데이터의 nunique 구해서 어떤 값을 one-hot-encoding 하면 좋을지 찾기
수치 데이터를 그대로 ordinal encoding 된 값을 그대로 사용해도 되지만 범주 값으로 구분하고자 하면 category 나 object 타입으로 변환하면 one-hot-encoding 할 수 있음
ordinal encoding => one-hot-encoding 실습 목적
코드
num_nunique = df.select_dtypes(include='number').nunique().sort_values() num_nunique[num_nunique<10]
-> 성공이 높아진다는 보장은 없다!!!
❓ 왜도와 첨도의 정확한 수치까지 알아야 할까?
❗ 정확한 수치까지는 모르더라도 시각화를 해보면 알 수 있다.
-> 왜도와 첨도는 변수가 수백개 될 때 전체적으로 왠도와 첨도가 높은 값을 추출해서 전처리 할 수 있음
✒❗데이터 시각화는 우리가 데이터 인사이트를 더 쉽게 찾을 수 있도록 도와주지만, 데이터 시각화에 의해 데이터를 잘못 해석하기도 하기 때문에 항상 주의해야함❗❗
num_cate_feature = df[log_features].nunique()
num_cate_feature = num_cate_feature[num_cate_feature < 20].index
num_cate_feature
num_log_feature = list(set(log_features) - set(num_cate_feature))
num_log_feature
df[num_log_feature] = np.log1p(df[num_log_feature])
df[num_log_feature].hist(figsize=(12, 8), bins=100);
❓ 수치데이터의 결측치를 0으로 채우면 안되는 값?
(현실세계에서 0이면 이상한 값)
❗ 키, 몸무게, 나이, 집 평수, 혈당, 인슐린수치, 혈압
-> 화장실 수, 2층 면적, 주차장 면적 -> 해당 시설이 없다면 0이 될 수 있음
✒️plt.show()는 그래프를 보여주는 역할
✒ 기존 주피터 에서는 그래프를 보여주는게 기본값이 아니었는데 마지막 줄에 그래프를 그리는 코드가 있다면 보여주는 것이 기본 값으로 변경
✒ plt.show()를 했을 때 주피터 버전에 따라 중복 출력이 될 수도 있는데 이때는 plt.show()를 지우면 됨
squared_features = ['YearRemodAdd', 'LotFrontage',
'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'GrLivArea','GarageArea']
df[squared_features].hist(figsize=(12, 8), bins=50)
df_square = df[ squared_features] ** 2
df_square.hist(bins=100);
-> 값을 강조해서 구분해서 보고자 할 때 주로 사용
🔷 append VS extend
1. append: 봉지과자를 통째로 넣음
a=[] a.append([1,2,3])
[[1,2,3]]
a=[] a.extend([1,2,3])
[1,2,3]
✒️ 과자봉지 = iterable 혹은 컨테이너
df_ohe = pd.get_dummies(df[feature_names])
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
y_valid_predict = cross_val_predict(model, X_train, y_train, cv=kf, n_jobs=-1)
방법 1.
(((y_valid_predict - y_train) ** 2).mean()) ** 0.5
방법 2.
np.sqrt((np.square(y_train - y_valid_predict)).mean())
방법 3.
from sklearn.metrics import mean_squared_error mean_squared_error(y_train, y_valid_predict) ** 0.5
`from sklearn.metrics import r2_score
r2_score(y_train, y_valid_predict)`
--윗 줄까지 모의고사 풀어봄--
학습과 예측
y_predict = model.fit(X_train, y_train).predict(X_test)
제출 파일 양식
submit = pd.read_csv('data\\house\\sample_submission.csv')
정답 옮겨 적기
submit['SalePrice'] = np.expm1(y_predict)
🔷 리더보드에 있는 점수와 동일한 스케일 점수를 미리 계산해 보기 위해서는 로그 적용한 값으로 계산해주지만
🔷 제출할 때는 지수함수를 적용해서 원래 스케일로 복원하여 제출해야함
❗❗❗ 내부에서 평가할 때는 제출받은 값에 로그를 취해서 점수를 평가하지만 제출할 때는 지수함수를 적용해서 제출해야함❗❗❗
csv 파일로 저장하기
submit.to_csv(file_name, index=False)
💥 수치형 데이터에 할 수 있는 전처리
-> 결측치 대체
=> 수치형 변수를 대체할 때는 원래의 값이 너무 왜곡되지 않는지 주의
-> 스케일링: standard, Min-Max, Robust
-> 변환: log
-> 이상치(너무 크거나 작은, 범위를 벗어나는 값) 제거 혹은 대체
-> 오류값(잘못된 값) 제거 혹은 대체
-> 이산화: cut, qcut
💥 범주형 데이터에 할 수 있는 전처리
-> 결측치 대체
-> 인코딩: label, ordinal, one-hot-encoding
-> 범주 중에 빈도가 적은 값은 대체하기
: 종속 변수 y와 한 개 이상의 독립변수 X와의 선형 상관 관계를 모델링하는 회귀 분석 기법
-> 선형 예측 함수를 사용해 회귀식을 모델링하고 알려지지 않은 파라미터는 데이터로부터 추정
`from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(drop='if_binary', handle_unknown='ignore')
train_ohe = ohe.fit_transform(train.select_dtypes(exclude='number'))
test_ohe = ohe.transform(test.select_dtypes(exclude='number'))
print(train_ohe.shape, test_ohe.shape)`
🔷 반환값이 np.array 형태이기 때문에 데이터 프레임으로 별도의 변환이 필요
df_train_ohe.index=train.index df_test_ohe.index=test.index
df_train= pd.concat([df_train_ohe, train.select_dtypes(include='number')], axis=1)
-> train과 인코딩 된 df_train의 행 수가 같은지 확인하고 칼럼이 늘었는지도 확인
X = df_train.drop(columns='y') y = df_train['y']
X_train, X_valid, y_train, y_valid = train_test_split(
X,y,test_size=0.2, random_state=42)
X_train.shape, X_valid.shape, y_train.shape, y_valid.shape
종속 변수 y와 한 개 이상의 독립 변수 X와의 선형 상관 관계를 모델링하는 회귀분석 기법
ex) ''아버지의 키가 크면 아들의 키도 큰가'' 를 알아보는 것
LinearRegression(
*,
fit_intercept=True,
normalize='deprecated',
copy_X=True,
n_jobs=None,
positive=False,
)
from sklearn.linear_model import LinearRegression
model = LinearRegression(n_jobs=-1)
model.fit(X_train, y_train) -> 학습
*R2 score 정확도 출력
model.score(X_valid, y_valid)
💥💥정리
-선형회귀보다 트리계열 모델을 사용하면 같은 데이터셋임에도 훨씬 나은 성능을 보임
-이상치도 포함되어 있음. 회귀모델을 이상치에 민감하기도 하고 다른 수치데이터에 대해 전처리가 많이 필요함
-선형회귀는 간단하고 이해하기 쉽다는 장점이 있음.
-선형회귀에 맞는 데이터셋을 사용한다면 좋은 성능을 낼 수 있음
💥 원핫인코딩을 범주형 변수에 해주고 수치데이터와 합치는 과정을 배움
💥 ordinal 인코딩 방법 학습
💥 concat -> 인덱스 값이 맞지 않으면 제대로 병합되지 않을 수 있기 때문에 인덱스 값에 유의가 필요
💥 기존에는 cross validation을 이용했지만 0801에서는 hold-out-validation 사용
💥 hold-out-validation 은 속도가 빠르지만 신뢰가 떨어짐
💥 train, valid, test => train, test split은 train과 test만 나눔
-> train을 다시 train, valid로 나눠줌
sns.scatterplot(data=train, x=train.index, y='y')
train = train[train['y']<200].copy()
ohe = OneHotEncoder(handle_unknown = 'ignore')
train_ohe = ohe.fit_transform(train.drop(columns='y'))
test_ohe = ohe.transform(test)
train_ohe.shape, test_ohe.shape
from sklearn.model_selection import train_test_split
X_test = test_ohe
X_train, X_valid, y_train, y_valid = train_test_split(
X, y, test_size=0.1, random_state=42)
-> test 사이즈를 0.1로 하여 train이 많이 학습할 수 있도록 함
✒️ 앙상블
: 여러 머신러닝 모델을 연결하여 더 강력한 모델을 만드는 기법
1. 랜덤 포레스트
2. 그래디언트 부스팅
✒️ 배깅
: 부스트 트랩을 통해 조금씩 다른 훈련 데이터에 훈련된 기초 분류기들을 결합
: 편향은 그대로 유지하면서 분산은 감소
✒️ 엑스트라 트리 모델
: 극도로 무작위화된 모델
: 약간 더 큰 편향 증가를 희생시키면서 모델의 분산을 조금 더 줄일 수 있음
주요파라미터
n_estimators: 숲에 있는 나무의 수
criterion: 분할의 품질을 측정하는 기능
max_depth: 트리의 최대 깊이
min_samples_split: 내부 노드를 분할하는데 필요한 최소 샘플 수
max_features: 최상의 분할을 찾을 때 고려해야할 기능의 수
특징
✒️ GBT: 그레디언트 부스팅
❓ GBM, XGBoost, LightGBM, 모델이름에 들어가는 G 는 무엇을 의미?
❗ 기울기, 경사
-> 손실함수 그래프에서 값이 가장 낮은 지점으로 경사를 타고 하강. 머신러닝에서 예측값과 정답값간의 차이가 손실함수인데 이 크기를 최소화시키는 파라미터를 찾기 위해 사용
✒️ GMB(Gradient Boosting Machine)
회귀 또는 분류 분석을 수행할 수 있는 예측 모향
❓ 성능에 고려 없이 GBM에서 훈련 시간을 줄이는 방법
❗ learning_rate == 학습률 == 보폭을 올린다
-> 보폭을 크게 하면 훨씬 빨리 걷게 된다. 그렇기 때문에 learning_rate 를 올리면 학습시간은 줄어들지만 제대로 된 loss(손실)가 0이 되는 지점을 제대로 찾지 못할 수도 있다.
❓ GBM은 왜 랜덤 포레스트와 다르게 무작위성이 없을까?
❗ 이전 오차를 보완해서 순차적으로 추출하기 때문
❓ absolute loss 는 지원은 하지만 squared loss 를 더 많이 사용할까?
❗ 기울기가 +, - 방향에 따라 같은 기울기가 나오기 때문에 방향은 알 수 있지만 기울기가 같아서 미분을 했을 때 방향에 따라 같은 미분값이 나와서 기울기가 큰지, 작은지 비교할 수 없다. 그래서 squared loss 를 더 많이 사용
✒️ XGBoost
: 모든 가능한 트리를 나열하여 최적 트리를 찾는 것은 불가능하므로 2차 근사식을 바탕으로 한 손실함수를 토대로 매 iteration마다 하나의 leaf로부터 가지를 늘려나는 것이 효율적
-> 손실함수가 최대한 감소하도록 하는 split point(분할점)를 찾는 것이 목표