Obdisian에 정리한 markdown을 html export한 뒤, Tistory로 옮긴 게시글.
(Obsidian 형식으로 써진 글이라 LaTex 등 일부 형식이 깨짐)
last update : 2026-02-26
Sklearn
Scikit Learn
머신러닝(간단한 supervised learning, non-supervised learning 위주.)을 위한 파이썬 라이브러리.
Based on Numpy , Scipy, Matplotlib
# Classifier / Regressor base strcuture
class SupervisedEstimator(...):
def __init__(self, hyperparam_1, ...):
self.hyperparm_1
...
def fit(self, X, y): # Train X, y
...
self.fit_attribute_ # something ends with _
return self
def predict(self, X): # Test X
...
return y_pred
def score(self, X, y): # Test y
...
return score # Classifier: 0~1, Regressor: -1~1
def _private_method(self):
...
...
Syntax
[ Pipeline ]
여러 Estimator API를 하나의 Pipeline에 담아 편리하게 사용할 수 있게 해준다.
Estimator API: .fit(X, y) (학습), .predict(X) (예측), .transform(X) (변환, 전처리), .fit_transform(X, y)들을 가진 class
from sklearn.pipeline import make_pipeline
#==== way 1: manually named =======================
pipeline = PipeLine([
('polynomial_features', polynomial_features),
('lr', linearRegression)
])
print(pipeline.named_step['lr'].coef_) # 각 객체는 `pipeline.named_step`에 있다.
#==== way 2: automatically named =======================
# 이름이 자동으로 생성된다. 이름은 class명을 소문자로(ex: linearregression)
pipe = make_pipeline(StandardScaler(),
KNeighborsClassifier(n_neighbors=3))
## 1 pipeline에는 최대 1 model. 여러 모델을 사용하려면 여러개의 pipeline을 만들어야 함.
pipe.fit(X_train, y_train)
pipe.predict(X_test)
[ Sample Data ]
from sklearn.datasets import load_diabetes
#==== Load Sample Data =======================
# Toy Dataset (zero-centered & normalized)
# [1: Details]
dataset = load_iris(as_frame=True)
# print(dataset.keys()) # kind of Dictionary
# .data # X # <class 'numpy.ndarray'>
# .target # y # <class 'numpy.ndarray'>
# .feature_names # names of X # <class 'list'>
# .target_names # names of y # <class 'numpy.ndarray'> # only for Classification data
# .DESCR # details for dataset # str
# ...
iris_X, iris_y = dataset.data, dataset.target
print(dataset.data.shape) # (150, 4)
print(dataset.feature_names) # ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
print(dataset.target_names) # ['setosa' 'versicolor' 'virginica']
print(dataset.DESCR) # more information of Dataset.
# [2: Quick]
diabetes_X, diabetes_y = load_diabetes(return_X_y=True, as_frame=True) # Same as above
## as_frame: return as pandas.DataFrame
# Get Large Dataset from Internet
fetch_...() # fetch계열은 용량이 커서 인터넷으로 `home/scikit_learn_data`에 저장한 뒤 불러옴.
#==== Generate Sample Data =======================
from sklearn.datasets import make_blobs
# Including high correlation, useless attribute
make_classifications() # for Classification
X, y = make_blobs(n_samples=n, n_features=p, centers=k, cluster_std=[0.8, 1, ...], random_state=0) # for Clustering
[ Data PreProcessing ]
X_train을 이용해서 fitting하고, fitting한 결과를 이용하여 transform함.
Handling NaN Data
Pandas에서는 NaN / Null / NaT를 동일하게 취급한다.
df.isnull().sum() ## 행 별로 NaN이 몇 개인가?
## 방법 1: 그냥 지워버림
df.dropna(axis=0) ## NaN이 있는 row(data)를 지움.
df.dropna(axis=1) ## NaN이 있는 column(feature)를 지움.
## 방법 2: 평균값(mean, median, mode)로 채워넣기
temp_mean = df['col1'].mean()
df['col1'].fillna(temp_mean)
## ?
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(missing_values=np.nan, strategy='mean') ## mean 사용
X = df.values ## np array로 변환
X = imputer.fit_transform(df.values)
Categorical Data: Nominal Data
특히 문자열.
Data의 Category 분류: 순서가 없는 data -> 항목별로 새로운 column으로 변환하기
ex) 옷의 색. Color: Blue, Yellow, Red -> Color_Blue: 0 or 1 / Color_Yellow: 0 or 1 / Color_Red 0 or 1
무의미한 Nominal이면 그냥 좀 지워라..
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
col = df['Color'] # ['Red', 'Yellow', 'Red', 'Blue']
#==== Label Encoding =======================
# For Classification / Tree-Regressor
encoder = LabelEncoder()
encoder.fit(col)
# print(encoder.classes_) # ['Blue' 'Red' 'Yellow']
labels = encoder.transform(col)
# print(labels) # Label Encoded data # [1, 2, 1, 0]
#==== One-hot Encoding =======================
# 1. 수동으로
col = col.reshape(-1, 1) # Input must 2d array.
encoder = OneHotEncoder()
encoder.fit(col)
labels = encoder.transform(col) # returns Sparse Matrix
# (0, 1) 1.0 # 대충 (row, col)에 1.0이라는 내용
# (1, 2) 1.0
# (2, 1) 1.0
# (3, 0) 1.0
labels = labels.toarray() # Sparse → Dense Matrix
# [[0. 1. 0.]
# [0. 0. 1.]
# [0. 1. 0.]
# [1. 0. 0.]]
# 2. 자동으로
pd.get_dummies(df[['Color', 'Role']]) # 숫자가 아닌 열이라면 여러 개 넣을 수 있다.
Categorical Data: Ordinal Data
Data의 Category 분류: 순서가 중요한 data -> 숫자로 바꾸기
ex) 옷의 사이즈. M L XXL -> 1 2 5
## 수동으로
mapping_dict = {'M': 1, 'L': 2, 'XXL': 5}
df['size_num'] = df['size'].map(mapping_dict) ## make new column
## 자동으로
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df['classlabel'] = le.fit_transform(df['classlabel'])
Data Scaling (standard / min_max / log)
data의 범위를 0-1로 바꾸거나, 단위를 표준화(cm-mm)할 때 사용.
※ Train/Validation/Test dataset 각각에 대해서 따로따로 Scaling하면 절대 안됨
standard scaler가 min-max scaler보다 oulier에 robust함.
log scaling은 feature unskew의 기능이 있어, unskew 시 gaussian distribution이 된다면, estimator의 성능 향상을 기대할 수 있다.
from sklearn.preprocessing import StandardScaler, MinMaxScaler
#==== Standard Scaling =======================
scaler = StandardScaler()
scaler.fit(X) # find avg, std
X_scaled = scaler.transform(X) # apply avg, std
#==== Min-max Scaling =======================
scaler = MinMaxScaler()
scaler.fit(X)
X_scaled = scaler.transform(X) # returns <class 'numpy.ndarray'>
#==== Log Scaling =======================
# 변환된 값을 원복할 수 있다. 1을 더하는 이유는 Underfitting을 방지하기 위해서이다.
# 특히 y에 많이 적용한다. 변환 시 더 학습이 잘 되는 gaussian의 형태로 변환된다.
X_scaled = np.log1p(X)
X = np.expm1(X_scaled) # 역변환도 가능하다.
# 한번에
X_scaled = scaler.fit_transform(X)
X_scaled = pd.DataFrame(X_scaled) # 다시 pd.dataframe으로
Binarizer
from sklearn.preprocessing import Binarizer
X = np.range(9).resize(3, 3) # (3x3) Matrix
binar = Binarizer(threshold=5) # for each data, data > threshold: 1, else: 0
X_ = binar.fit_transform(X)
[ Model Selection ]
아래로 갈수록 강화버전.
최종 형태는 GridSearchCV인 듯.
Train/Test Dataset Split
X, y →
Train: For train model
Validation: For hyperparameter tuning
Test: For Evaluate model
from sklearn.model_selection import train_test_split
#==== 2-fold (Train/Test) =======================
# X -> X_temp, X_test
X_train, X_test, y_train, y_test = \
train_test_split(X, y, test_size=0.2,
shuffle=True, random_state=123, stratify=y)
#==== 3-fold (Train/Validation/Test) =======================
# X -> X_temp, X_test
X_temp, X_test, y_temp, y_test = \
train_test_split(X, y, test_size=0.2,
shuffle=True, random_state=123, stratify=y)
# X_temp -> X_train, X_valid
X_train, X_valid, y_train, y_valid = \
train_test_split(X_temp, y_temp, test_size=0.2,
shuffle=True, random_state=123, stratify=y_temp)
KFold / StratifiedKFold / cross_val_score / cross_validate
KFold (K=5) → ░: train set / █: test set / iter=5 (for Regression)
1: █░░░░ → model fit, Evaluate
2: ░█░░░ → "
3: ░░█░░
4: ░░░█░
5: ░░░░█
StratifiedKFold: 각 fold가 균일한 class분포를 갖도록 개선한 버전. (for Classification)
cross_val_score: 위의 folding → fit → score을 알아서 한 줄로 해주는 함수.
cross_validate: 위와 같으나, return에 여러 개의 scoring, 실행 시간 등을 같이 반환하는 함수.
from sklearn.model_selection import KFold, StratifiedKFold, cross_val_score, cross_validate
#==== KFold =======================
kfold = KFold(n_splits=5) # K=5
kfold_accuracy = []
for train_idx, test_idx in kfold.split(X): # train_idx: range(0, n), test_idx: range(n+1, 5n)
#==== StratifiedKFold =======================
skfold = StratifiedKFold(n_splits=5) # K=5
kfold_accuracy = []
for train_idx, test_idx in skfold.split(X, y) # requires y for even class distribution
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
# model Fit
estimator.fit(X_train, y_train)
y_pred = estimator.predict(X_test)
# model score
acc = accuracy_score(y_test, y_pred)
kfold_accuracy.append(acc)
print(np.mean(kfold_accuracy))
#==== cross_val_score =======================
scores = cross_val_score(estimator, X, y, scoring='accuracy', cv=5) # K=5 / accuracy_score
scores = cross_val_score(estimator, X, scoring='accuracy', cv=5) # y=None: Regression?
print(np.mean(scores))
#==== cross_validate =======================
cv_results = cross_validate(model, X, y, scoring='accuracy', cv=5, return_estimator=True)
print(scores)
GridSearchCV
[ Model Selection ]과 [ Hyerparameter Tuning ]을 동시에 한다.
시간이 조금 걸릴 수 있다.
from sklearn.model_selection import GridSearchCV
#==== GridSearchCV =======================
# Fit Best Model
# example: fit model 30 times. 3(hyperparam 1) × 2(hyperparam 2) × 5(folds) = 30.
hyperparams = {'max_depth': [1, 2, 3], # hyperparamters of DecisionTreeClassifier.
'min_samples_split': [2, 3]} # Dictionary
grid_search = GridSearchCV(estimator, param_grid=hyperparams, scoring='neg_mean_squared_error', cv=5, n_jobs=-1) # K = 5 # refit=True (default): re-fit model with best hyperparamer set. # n_jobs: count of CPU core usage. -1: ALL
grid_search.fit(X_train, y_train) # internally seperate [train] to [train/validation] folds.
# Get Score
df = pd.DataFrame(grid_search.cv_results_) # Dictionary -> pd.DataFrame for readability
print(df) # pd.DataFrame has 6(2*3) ROWS.
print(df['rank_test_score']) # best(max 'mean_test_score') hyperprameter set.
print(grid_search.best_params_) # {'max_depth': 3, 'min_samples_split": 2}
print(grid_search.best_score_) # 0.974...
# Test Model
estimator = grid_search.best_estimator_
y_pred = estimator.predict(X_test)
print(accuracy_score(y_test, y_pred))
Hyperparameter Tuning (Baysian Optimization)
#==== HyperOpt =======================
from hyperopt import hp
Models
# Train
model = Model(random_state=123)
model.fit(X_train, y_train)
# Test
pred = model.predict(X_test)
# Extract Hyperparameter
print(model.get_params())
[ Supervised Learning]
Estimator: 지도학습의 모든 모델들.fit(): 학습.predict(): 추론
Recommended:
Regressor:
Classifier: XGBoost, LightGBM
Regressor
VIsualize Regressor Coefficients
coef = pd.Series(model.coef_, index=X.columns) # get coefficients
coef_sorted = coef.sort_values(ascending=False) # Ordering
sns.barplot(x=coef_sorted.values, y=coef_sorted.index) # draw to barplot
Linear Regression
Multi-Collinearity 문제: Feature 간의 상관관계가 매우 높으면 분산이 커져 오류에 매우 민감해짐 ← 차원 축소 OR 규제 적용
from sklearn.linear_model import LinearRegression
#==== Simple Linear Regression =======================
regr = LinearRegression()
## Train model
regr.fit(X_train, y_train)
## Test model
diabetes_y_pred = regr.predict(diabetes_x_test)
regr.coef_ # returns coefficient(weight) of model. `W` (np.ndarray)
regr.intercept_ ## intercept of model. w_0 (np.float64)
# (Analysis)
# 어떤 feature가 결과에 얼마나 중요한 영향을 미치는 지 알아볼 수 있다.
coefficient = pd.Series(data=regr.coef_, index=X.columns) # feature명에 따른 계수
coefficient.sort_values(ascending=False) # 중요도 내림차순 정렬
# Feature 2 3.2 # Feature 2가 y에 가장 영향이 크다.
# Feature 1 0.1
# Feature 3 -1.0
Polynomial Regression
Polynomial Regression도 Linear Regression이다.
feature를 단순히 로 전처리함으로써 구현한다.
from sklearn.preprocessing import PolynomialFeatures
#==== Polynomial Regression =======================
# 1. preprocessing
poly = PolynomialFeatures(degree=2) # 2차로 mapping
X_degree_2 = poly.fit_transform(X)
Lasso / Ridge Regression / ElasticNet
Objective() = Loss() + Regression()
Regression()
Lasso :
Ridge :
Elasticnet :
from sklearn.linear_model import Lasso, Rigde, ElasticNet
#==== Lasso Regression =======================
lasso = Lasso(alpha=10)
neg_mse_scores = cross_val_score(lasso, X, y, scoring="neg_mean_scores", cv=5)
rmse_scores = np.sqrt(-1*neg_mse_scores)
avg_rmse = mp.mean(rmse_scores)
#==== Ridge Regression =======================
ridge = Ridge(alpha=10)
#==== ElasticNet =======================
elasticnet = ElasticNet(alpha=10, l1_ratio=0.7) # l1_ratio + l2_ratio = 1
KNN Classifier
from sklearn.neighbors import KNeighborsClassifier
from mlxtend.plotting import plot_decision_regions
knn_model = KNeighborsClassifier(n_neighbors=3) ## number of nearst neighbos: 3
knn_model.fit(X_train[:, 2:], y_train)
plot_decision_regions(X_train[:, 2:], y_train, knn_model)
plt.xlabel('petal length[cm]')
plt.ylabel('petal width[cm]')
plt.show()
Classifier
Logistic Regression
Linear Regression에 sigmoid()를 적용하여 확률적으로 class를 분류하기.
hyperparameter:
penalty='l2': Regularization(Lasso / Ridge).
C: power of Regularization. C↑: overfitting↑, C↓: underfitting↑. ()
solver='lbfgs' : 최적화 함수 이름. 성능은 비슷비슷하다고 함.
max_iter: 수렴할 때까지 반복하는 횟수
from sklearn.linear_model import LogisticRegression
logiRegr = LogisticRegression(C=1e5)
logiRegr.fit(X_train, y_train)
SVC (Support Vector Classifer)
from sklearn import svm
## Model 1
svclf = svm.SVC(kernel="linear", C=1e0) ## Support Vector CLassiFier
## Model 2
svclf = svm.LinearSVC(C=1e0, max_iter=10000) ## much faster than above in linear
svclf.fit(X_train_std, y_train)
y_pred = svclf.predict(X_test_std)
Tree based (Regressor & Classifier)
model.featureimportances
DecisionTreeRegressor / DecisionTreeClassifer
Decision Tree: 가장 기본적인 Tree.
반복적으로 기준(규칙)에 따라, Entrophy가 작아지도록, Feature Space를 분할함.
Feature Scaling이나 Regularizaion 등 전처리가 없어도 Robust하다.
규칙이 많다 → Overfitting의 가능성이 높다 → Ensemble에 유리하다.
hyperparameter=default:min_samples_split=2: node를 분할하기 위한 최소한의 sample 수min_samples_leaf: 분할 후에 node에 존재해야 할 최소한의 sample 수max_features=None: 최적의 분할을 위해 고려할 최대 feature 수.
int로 지정: 대상 feature 수,
float로 지정: 전체 중 대상 feature의 비율
'sqrt' OR 'auto': 전체개수
'log': 전체개수
'None': 전체 개수max_depth=None: tree의 최대 depth. None은 무제한.max_leaf_nodes: leaf node의 최대 개수
from sklearn.tree import DecisionTreeRegressor, DecisionTreeClassifier
dt_c = DecisionTreeClassifier(random_state=0, max_depth=4)
dt_c.fit(X_train, y_train)
pred = dt_c.predict(X_test)
print(dt_c.feature_importances_) # 각 feature의 중요도(geni 계수를 얼마나 개선했는지)를 정규화된 값으로 나타냄.
sns.barplot(x=dt_c.feature_importances_, y=df.feature_names) # to graph
Tree Based Ensemble
성능이 좋지만, 오래걸리고, hyperparameter가 많다.
- Voting: 서로 다른 model을 평균내는 방식
- Hard Voting: 다수결로 Voting
- Soft Voting: pred의 확률을 모두 평균내서 Voting (흔히쓰임)
- Bagging: data sampling을 서로 다르게 하는 방식
- Boosting: 여러 개의 분류기를 학습하되, 이전 model이 다음 model로 weight를 적용
Voting model
VotingRegerssor / VotingClassifier
from sklearn.ensemble import VotingClassifier
# different models for voting
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
lr_clf = LogisticRegression(solver=liblinear)
knn_clf = KNeighborsClassifier(n_neighbors=8)
#==== Voting Classifier =======================
vot_clf = VotingClassifier(estimators=[('LR', lr_clf), ('KNN', knn_clf)], voting='soft')
vot_clf.fit(X_train, y_train)
pred = vot_clf.predict(X_test)
Bagging models
RandomForestRegressor / RandomForestClassifer (emsemble)
ensemble 모델 중 상대적으로 빠름.
n_estimators=10 ensemble에 쓸 모델 개수
나머지는 Decision Tree의 hyperparameter와 99% 같다.
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifer
rfRegr = RandomForestRegressor(random_state=0, n_estimators=1000)
scores = cross_val_score(rfRegr, X, y, scoring="neg_mean_squared_error", cv=5)
Boosting models
GBM: GradientBoostringRegressor / GradientBoostringClassifier (ensemble)
weak learner들을 순차적으로 학습-예측하면서,
잘못된 data에 weight 부여를 통해 오류를 개선하면서 학습하는 방식.
Gradient Descent로 weight를 업데이트한다.
hyperparametersloss='deviance': Gradient Descent 시 사용할 Loss Function.learning_rate=0.1: Gradient Descent 시 사용할 learning rate. 작을수록 성능 증가, 오래걸림n_estimators=100: weak learner의 개수.subsample=1: weak learner가 학습에 사용할 data의 sampling rate
나머지는 Decision Tree의 hyperparameter와 같다.
from sklearn.ensemble import GradientBoostingRegressor, GradientBoostringClassifier
gbRegr = GradientBoostingRegressor(random_state=0, n_estimators=500)
gbRegr.fit(X_train, y_train)
pred = gbRegr.predict(X_test)
XGBRegressor / XGBClassifier
GBM에서 속도 개선(병렬 처리), Overfitting Regularization(자체 pruning, cross-evaluation) 기법 추가.
C++로 구현된 sklearn 외부 library지만, sklearn에서 쓸 수 있게 wrapper를 지원한다.
hyperparameters
너무 많아서 생략. 파이썬머신러닝완전가이드 228p(244/722) 참고.
from xgboost import XGBRegressor, XGBClassifier
xgbRegr = XGBRegressor(n_estimators=1000)
LGBMRegressor / LGBMClassifier
XGBoost보다 훨씬 빠르지만, 예측 성능은 비슷하다.
대신 data가 적을 경우 Overfitting의 가능성이 높다.
from lightgbm import LGBMRegressor, LGBMClassifier
lgbmRegr = LGBMRegressor(n_estimators=1000)
Custom Estimator
from sklearn.base import BaseEstimator
class MyClassifier(BaseEstimator):
def fit(self, X, y=None):
# Fit here
def predict(self, X):
pred = np.zeros((X.shape[0], 1))
# Predict here
return pred
Stacking
ensemble 기법 중 하나.
여러 모델들의 prediction들을 모아, 이를 새로운 X'로 새로운 모델을 훈련하는 방식.
# Basic Stacking Theory Code
# multiple models here
knn_clf = KNeighborsClassifier(n_neighbors=4)
rf_clf = RandomForestClassifier(n_estimators=100, random_state=0)
ada_clf = AdaBoostClassifier(n_estimators=100)
knn_clf.fit(X_train, y_train)
rf_clf.fit(X_train, y_train)
ada_clf.fit(X_train, y_train)
pred1 = knn_clf.predict(X_test)
pred2 = rf_clf.predict(X_test)
pred3 = ada_clf.predict(X_test)
X_final = np.array([pred1, pred2, pred3]).T # shape(N, 3)
# meta model here
lr_final = LogisticRegression()
pred_final = lr_final.predict(X_final)
# better Accuracy found
다양한 관점의 모델을 섞음으로써 모델의 전체적인 performace향상을 기대할 수 있다.
from sklearn.linear_model import LinearRegression, RidgeCV
from sklearn.ensemble import StackingRegressor
def stacking(train_x, train_y, test_x, test_y):
# 1. 기본 모델 정의
base_models = [
# LInear Models
('lr', LinearRegression()),
# Tree-based Models
('rf', RandomForestRegressor(random_state=42)),
('lgb', LGBMRegressor(random_state=42, verbose=-1)),
('gb', GradientBoostingRegressor(random_state=42)),
('xgb', XGBRegressor(random_state=42)),
# Other Models
('kn', KNeighborsRegressor())]
# 2. 메타 모델 정의 (Final Estimator)
#meta_model = RidgeCV(cv=5)
meta_model = LinearRegression()
# 3. 스태킹 앙상블 모델 생성
stacking_model = StackingRegressor(
estimators=base_models,
final_estimator=meta_model,
cv=5,
n_jobs=-1,
verbose=2, # How much talk for debugging
passthrough=False # 기존 데이터를 메타 모델에 다시 넣지 않고, 개별 모델의 예측값만 사용 (True로 하면 성능이 오를 때도 있음)
)
# 4. 모델 학습
print("Stacking 모델 학습 중...")
stacking_model.fit(train_x, train_y)
# 5. 예측 및 평가
y_pred = stacking_model.predict(test_x)
final_r2 = r2_score(test_y, y_pred)
final_mae = mean_absolute_error(test_y, y_pred)
final_rmse = np.sqrt(mean_squared_error(test_y, y_pred))
return final_r2, final_mae, final_rmse
[ Unsupervised Learning ]
estimator?.fit(): 사전 구조 작업.transform(): 실제 작업.fit_transform(): 동시에
Dimentionality Reduction
PCA (Principal Component Analysis)
data의 분산을 최대로 하는, orthogonal한 축(Principle Component)들 찾기:pd.DataFrame.corr()에서 상관도가 높은 column을 제거하는 기능도 있다.
고유벡터 : i번째로 분산을 최대로 하는 새로운 축.
고윳값 : 새로운 축 가 전체 데이터를 얼마나 잘 설명하는지에 대한 수치. 이다.
따라서 data를 설명하는 새로운 축의 벡터 :
X = df.iloc[:, :-1]
#==== Scaling =======================
# PCA 전에, feature의 Unit 차이로 인한 왜곡 방지를 위해 scaling.
from sklearn.preprocessing import StandardScalar
X_scaled = StandardScalar().fit_transform(X) # target을 제외한 모든 값에 대해.
#==== PCA =======================
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_ = pca.fit_transform(X)
print(pca.explained_variance_ratio_) # [0.73, 0.21] # 각 축이 데이터를 얼마나 잘 설명하는지.
df_pca = pd.DataFrame(X_, columns=['pca_1', 'pca_2'])
df_pca['y'] = df['y']
#==== SVD =======================
# PCA는 내부적으로 SVD로 구성되어 있다.
# SVD는 PCA와 달리 Sparse Matrix에 대한 변환도 가능하다.
from sklearn.decomposition import TruncatedSVD
tsvd = TruncatedSVD(n_components=2) # truncate 2 Principle Component
tsvd.fit(X)
X = tsvd.transform(X) # 결과는 PCA와 거의 동일하다.
LDA (Linear Discriminant Analysis)
Clustering이지만, 학습에 y label이 필요하므로, 비지도학습이 아닌 지도학습이다.
SVD와 비슷하지만, Classification에서 사용하기 좋다.
class 간 분산()을 최대화하고, class 내부 분산()를 최소화하는 관점이다.
#==== Scaling =======================
# LDA 전에, feature의 Unit 차이로 인한 왜곡 방지를 위해 scaling.
from sklearn.preprocessing import StandardScalar
df_scaled = StandardScalar().fit_transform(df)
#==== LDA =======================
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis(n_components=2)
lda.fit(df_scaled, df['y']) # y label이 필요하다.
df_lda = lda.trasform(df_scaled)
print(df_lda.shape)
NMF (Non-Negative Matrix Factorization)
NMF도 Low-Rank Approximation의 일종이다.
는 의 행에 대해 잠재요소의 값과 대응되며,
는 의 열에 대해 잠재 요소가 어떻게 구성되었는지는 나타낸다.
이미지/텍스트 데이터/추천 에서 많이 사용.
#==== NMF =======================
from sklearn.decomposition import NMF
nmf = NMF(n_components=2) # k=2
nmf.fit(X)
X_nmf = nmf.transform(X)
Clustering
Data가 어떻게 흩어져 있는지에 따라 최적의 방법이 다르다.
K-means Clustering (K-means++)
- 쉽고 간결하다.
- Feature이 매우 많으면 정확도가 떨어진다.(차원축소필요)
- 각 Cluster가 원형의 분포를 가질 때 유리하다.
hyperparameter:n_clusters: cluster kinit=k-means++max_iter=300: 수렴할 때까지 최대 반복 횟수
#==== K-Means++ =======================
from sklearn.cluster import KMeans
km = KMeans(n_clusters=k, random_state=0)
## n_init=10 (random restarts with random initializers)
## max_iter=300
km.fit(X)
print(km.cluster_centers_) # np.ndarry # pos of cluster centers.
print(km.labels_) ## np.ndarry # cluster labels of X
print(km.inertia_) ## SSE. 135.92823795402757 (
km.predict(X_new) ## equal to above. but can be applied to new data.
Mean Shift
K-means clustering과 비슷하나, 새로운 군집 중심을 찾을 때
Kernel Density Estimation을 이용한다.
kernel(gaussian)의 bandwidth에 따라 peak의 개수가 바뀌고, 각 peak가 새로운 cluster 중심이 된다.bandwidth ↓: overfitting 증가, cluster 수 증가bandwidth ↑: underfitting 증가, cluster 수 감소
#==== Mean Shift =======================
from sklearn.cluster import MeanShift
meanshift = MeanShift(bandwidth=0.8)
cluster_labels = meanshift.fit_predict(X)
#==== Find best bandwidth =======================
from sklearn.cluster import estimate_bandwidth
best_bandwidth = estimate_bandwidth(X)
Gaussian Mixture (GMM)
EM algorithm을 이용해, 2가지 반복적으로 구함으로써, 최적의 cluster에 점점 근사함.
- 각 cluster에 해당하는 gaussian의 average와 variance를 구함.
- 각 data가 어떤 cluster에 해당하는지 구함.
- 각 Cluster가 길쭉한 분포를 가질 때 유리.
hyperparametersn_components: gaussian의 개수(=cluster의 개수)
from sklearn.mixture import GaussianMixture
gm = GaussianMixture(n_components=3, random_state=0)
cluster_labels = gm.fit_transform(X)
Agglomerative Clustering
from sklearn.clustring import AgglomerativeClustering
agg = AgglomerativeClustering(n_clusters=5, linkage='ward')
agg.fit(X)
print(agg.fit_predict(X)) ## fit and predict. np.ndarry of cluster index. shape (n, )
####### Draw Dendrogram
from scipy.cluster.hierarchy import dendrogram, ward
import matplotlib.plot as plt ## ?
## Apply the ward clustering to the data array X
## The SciPy ward function returns an array that specifies the distances
## bridged when performing agglomerative clustering
linkage_array = ward(X)
## Now we plot the dendrogram for the linkage_array containing the distances
## between clusters
dendrogram(linkage_array)
## Mark the cuts in the tree that signify two or three clusters
ax = plt.gca()
DBSCAN
Density Based Spatial Clustering of Application with Noise
밀도 기반 알고리즘.
- 각 Cluster가 복잡한 구조를 가질 때 유리함. ex) 도넛 안의 도넛 같은 구조
Data를 3가지로 분류한다. Core Point와 Neighbor Point가 Cluster가 되고, Border Point는 Noise로 취급한다.
- Core Point : 범위 epsilon 안에 min_sample 개 이상의 data와 인접한 point
- Neighbor Point : Core Point는 아니지만 Core Point와 인접한 point
- Border Point : 나머지 Outlier
hyperparametereps: 각 데이터를 중심으로 epsilon만큼의 거리. 일반적으로 1 이하로 지정.min_samp: epsilon 범위 안에 몇 개?
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.6, min_samples=4)
lables = dbscan.fit_predict(X)
#print(labels.unique()) # [-1, 0, 1, 2] # -1 은 Noise, 나머지는 cluster
Evaluate Clustering & Visualize
Silhouette Score1: 근처의 군집과 멀리 떨어짐(분리가 잘 된 것)0: 근처의 군집과 인접합-1: 근처의 군집과 구분이 불가능함.
그리고 개별 sample의 silhouette score가 전체 silhouette score의 평균에서 멀리 떨어지지 않은 것이 좋은 clustering.
#==== Silhouette Analysis =======================
from sklearn.metrics import silhouette_samples, silhouette_score
X_silhouette_coeff = silhouette_samples(X, labels) # for each data. shape=(n,)
X_silhouette_score = silhouette_score(X, labels) # avg silhouette score
# Get silhouette Coefficient by Cluster
df['cluster'] = labels
df['silhouette coeff'] = X_silhouette_coeff
df.groupby('cluster')['silhouette coeff'].mean()
# cluster
# 0 0.417320
# 1 0.798148
# 2 0.451105
df.groupby('cluster')['silhouette coeff'].value_counts()
# target gm_cluster count
# 0 0 50
# 1 2 45
# 1 5
# 2 1 50
[ Performance Measurement (Metrics) ]
For Regressor - Errors
from sklearn.metrics import mean_absolute_error, mean_squared_error, mean_squared_log_error, r2_score
#==== Errors =======================
# MAE
score = mean_absolute_error(y, y_pred) # API
scoring='neg_mean_absolute_error' # scoring option in `cross_val_score` OR `GridSearchCV`
# MSE
mean_squared_error(y, y_pred)
scoring='neg_mean_squared_error' # `neg_` means negative(-1*MSE): scoring=big_value means good.
# RMSE
np.sqrt(mean_sqaured_error(y, y_pred))
scoring='neg_root_mean_squared_error'
# MSLE
mean_squared_log_error(y, y_Pred)
scoring='neg_mean_squared_log_error'
# R^2
r2_score(y, y_pred)
scoring='r2'
#==== Errors (Custom) =======================
# RMSLE
squared_error = (np.log1p(y) - np.log1p(y_pred))**2
score = np.sqrt(np.mean(squared_error))
For Classifier - Confusion Matrix / Classification Report / Metrics...
data = load_breast_cancer()
# Fit & Predict
X_train, X_test, y_train, y_test = train_test_split(
data.data, data.target, stratify=data.target, random_state=0)
lr = LogisticRegression().fit(X_train, y_train)
y_pred = lr.predict(X_test)
#==== Confusion Matrix =======================
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
print(confusion_matrix(y_test, y_pred)) ## normalize='true' or 'pred'
#== Example for binary classification ==
## predicted Neg, Positive
## actual Negative [TN , FP]
## actual Positive [FN , TP] ←- dtype=int64
ConfusionMatrixDisplay.from_estimator(lr, X_test, y_test, cmap="gray_r") # Same as above, but draws Heatmap with matrix
#==== Classification Report =======================
from sklearn.metrics import classification_report, precision_score, recall_score, f1_score
print(classification_report(y_test, y_pred)) #
## precision recall f1-score support
## class 0 0.90 0.95 0.92 100
## class 1 0.70 0.50 0.58 20
##
## accuracy 0.88 120
## macro avg 0.80 0.73 0.75 120
## weighted avg 0.87 0.88 0.87 120
#==== Metrics =======================
# Precision: (TP) / (TP + FP) # Actual P in P_predicted ratio
precision_score(...)
# Recall(=TPR): (TP) / (TP + FN) # Actual P in P_actual
## Important when predict T as F is CRITICAL.
print(recall_score(y_test, y_pred, average="macro")) ## average="weighted"
# Accuracy: (TN + TF) / (total)
## Same as classification_report[f1-score, accuracy]
print(accuracy_score(y_test, y_pred)) # (TP + TN) / (total) # Bad when Unbalanced Classes
## lr.score(X_test, y_test) # Same as accuracy_score(), but model-side method
print(balanced_accuracy_score(y_test, y_pred)) # Similar to (recall, macro avg)
# F1-score:
print(f1_score(y_test, y_pred, average="weighted"))
조화평균
For Classifier - Prediction Threshold / PR(Precesion-Recall) Curve / ROC curve & AUC score
PR(Precision-Recall) Curve:
Prediction의 Threshold를 바꿈에 따라 Recall(x축)과 Precision(y축)의 그래프
Precision과 Recall은 trade-off 관계에 있다.
그래프의 오른쪽 위의 점일수록 최적의 Threshold
ROC(Reciever Operation Characteristic) Curve:
Prediction의 Threshold를 바꿈에 따라 FPR(x축)과 TPR(Recall)(y축)의 그래프
그래프의 왼쪽 위의 점일수록 최적의 Threshold
AUC(Area Under Curve) Score
ROC Curve 아래의 면적. 1에 가까울수록 좋음.
from sklearn.metrics import precision_recall_curve, plot_precision_recall_curve
roc_curve, roc_auc_score, plot_roc_curve
#==== Classification Prediction Threshold =======================
# Change Prediction Threshold in Classification. - instead of `y_pred = model.predict(X_test)`
## hyperparameter: threshold. # Tune with Accuracy/Recall/Precision
y_pred_proba = model.predict_proba(X_test)[:, 1] # 각 data별로 각 class(COL)에 속할 확률을 반환. # second column means Positive class Ratio in Binary Classification.
y_pred = y_pred_proba > 0.3 ## default 0.5 (probability)
# 기준을 0.3으로 낮춤 -> 좀 더 후해짐 -> True로 판정할 확률 증가 -> Recall ↑, Precision ↓
#==== PR curve =======================
# Get Scores
precisions, recalls, thresholds = precision_recall_curve(y_test, model.predict_proba(X_test)[:, 1]) # shape: (nx1)
# Draw Plot
plot_precision_recall_curve(model, X_test, y_test, name="123")
#==== ROC curve & AUC score =======================
# Get Scores
fpr, tpr, thresholds = roc_curve(y_test, model.predict_proba(X_test)[:, 1])
# Get AUC Score
auc_score = roc_auc_score(y_test, y_pred_proba)
# Draw Plot
plot_roc_curve(model, X_test, y_test, name="123")
## Names of other metrices
from sklearn.metrics import SCORES
print("\n".join(sorted(SCORES.keys())))
'Programming Language > Python' 카테고리의 다른 글
| Seaborn (0) | 2026.01.20 |
|---|---|
| Matplotlib (0) | 2026.01.20 |
| Pandas (0) | 2026.01.20 |
| Numpy (0) | 2026.01.17 |