Discover us

About us

Projects

Blog

Events

Members

Development Blog

GDGoC CAU 개발자와 디자이너의 작업 과정과
결과물을 공유하는 공간입니다.

어떻게 프로젝트를 시작하게 되었고,
진행하면서 느낀 개발자와 디자이너의
생생한 스토리를 직접 확인해보세요!

Development

ML Chap 2. Machine Learning Project-2

  • #DS/ML/DL
  • HyeWon Lee
  • 2023. 9. 18.

ML Chap 2. Machine Learning Project-2

Machine Learning Project(2)

Hands-on-Machine-Learning Chap2
이전 project 과정에 이어서

4. Prepare the data for Machine Learning algorithms.

데이터 준비를 수동이 아니라 함수를 만들어 자동화하는 이유 -> 데이터 변환이 쉽고 어떤 조합이 좋은지 확인하는데 편리, 변환 라이브러리를 점차 구축하게 됨, 새 데이터 주입 전에 함수 사용 가능
housing = strat_train_set.drop("median_house_value", axis=1)housing_labels = strat_train_set["median_house_value"].copy()
separate the predictors and the labels since we don’t necessarily want to apply the same transformations to the predictors and the target values

1) Data Cleaning

누락된 attribute를 처리하는 방법 - option1)해당 구역 제거 - option2) 전체 특성 삭제 - option3) 어떤 값으로 채우기(0, mean, median…)
housing.dropna(subset=["total_bedrooms"]) # option 1housing.drop("total_bedrooms", axis=1) # option 2median = housing["total_bedrooms"].median() # option 3housing["total_bedrooms"].fillna(median, inplace=True)
Imputer는 누락된 값을 쉽게 다루도록 함.
from sklearn.impute import SimpleImputerimputer = SimpleImputer(strategy="median")housing_num = housing.drop("ocean_proximity", axis=1)imputer.fit(housing_num)imputer.statistics_housing_num.median().values

2) Handling Text and Categorical Attributes

housing_cat = housing["ocean_proximity"]housing_cat_encoded, housing_categories = housing_cat.factorize()housing_cat_encoded[:10]
categorical인 ocean_proximaty를 numerical로 변환
housing_categories
0 category에 1category보다 4category가 더 비슷하다는 문제. one-hot encoding ->one-hot vector로 바꿔주기
from sklearn.preprocessing import OneHotEncodercat_encoder = OneHotEncoder()housing_cat_1hot = cat_encoder.fit_transform(housing_cat_encoded.reshape(-1,1))housing_cat_1hot
fit_transform() method는 2차원 배열을 넣어줘야 함. 1차원 배열인 housing_cat_encoded 구조를 바꿔야 함.
a SciPy sparse matrix - 수천개의 categories가 있는 categorical features일 때 효율적. - OneHotEncoder하면 열이 수천개인 행렬로 변하고 각 행은 1이 하나뿐이고 그 외는 모두 0인 행렬이 됨. 메모리 낭비를 피하기 위해 sparse matrix는 0이 아니 원소의 위치만 저장함.
housing_cat_1hot.toarray()
to convert it to a (dense) NumPy array, just call the toarray() method
text category를 numerical category로, numerical category를 one-hot vector로 바꿔주는 이 두 가지 변환을 CategoricalEncoder를 사용하여 한번에 처리 가능
cat_encoder.categories_

3) Custom Transformers

from sklearn.base import BaseEstimator, TransformerMixinrooms_ix, bedrooms_ix, population_ix, households_ix = 3, 4, 5, 6class CombinedAttributesAdder(BaseEstimator, TransformerMixin): def __init__(self, add_bedrooms_per_room = True): # no *args or **kargs self.add_bedrooms_per_room = add_bedrooms_per_room def fit(self, X, y=None): return self # nothing else to do def transform(self, X, y=None): rooms_per_household = X[:, rooms_ix] / X[:, households_ix] population_per_household = X[:, population_ix] / X[:, households_ix] if self.add_bedrooms_per_room: bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix] return np.c_[X, rooms_per_household, population_per_household, bedrooms_per_room] else: return np.c_[X, rooms_per_household, population_per_household]attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False)housing_extra_attribs = attr_adder.transform(housing.values)

4) Feature Scaling

the input numerical가 너무 다른 scales을 가질 때 머신러닝 알고리즘은 잘 작동하지 않는다. scaling the target values는 일반적으로 요구되지 않는다.

scaling 방법

(1) min-max scaling(nomalization)

data에서 min을 빼고 (max-min)로 나누면 0~1 범위에 들도록 값을 이동할 수 있다. 0~1 범위를 원하지 않으면 feature_range hyperparameter로 범위 변경 가능.
  • > 범위의 상한 하한이 있음

(2) standardization

먼저 mean을 뺀다. (그래서 standardization을 하면 mean이 0이 됨.) 그 다음 sd로 나누어 the resultiong distribution이 unit variance를 갖도록 한다.
  • > 범위의 상한 하한이 없어서 범위가 요구되는 알고리즘에서는 문제 발생. -> outier에 영향을 덜 받음.

5) Transformation Pipelines

Pipeline : A sequence of data processing components
# numerical attributes 처리from sklearn.pipeline import Pipelinefrom sklearn.preprocessing import StandardScalernum_pipeline = Pipeline([ ('imputer', SimpleImputer(strategy="median")), ('attribs_adder', CombinedAttributesAdder()), ('std_scaler', StandardScaler()), ])housing_num_tr = num_pipeline.fit_transform(housing_num)
from sklearn.compose import ColumnTransformernum_attribs = list(housing_num)cat_attribs = ["ocean_proximity"]full_pipeline = ColumnTransformer([ ("num", num_pipeline, num_attribs), ("cat", OneHotEncoder(), cat_attribs), ])housing_prepared = full_pipeline.fit_transform(housing)

5. Select a model and train it.

1) Training and Evaluation on the Traning Set

from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression()lin_reg.fit(housing_prepared, housing_labels)
some_data = housing.iloc[:5]some_labels = housing_labels.iloc[:5]some_data_prepared = full_pipeline.transform(some_data)print("Predictions:", lin_reg.predict(some_data_prepared))print("Labels:", list(some_labels))
#mean_square_error 함수로 전체 training set에 대한 regression model의 RMSE 측정from sklearn.metrics import mean_squared_errorhousing_predictions = lin_reg.predict(housing_prepared)lin_mse = mean_squared_error(housing_labels, housing_predictions)lin_rmse = np.sqrt(lin_mse)lin_rmse
median_housing_values의 대부분이 120000에서 265000 사이의 값이었는데 prediction error가 68628인 것은 좋지 않다. underfitting됨
underfitting 해결 방법
  • more powerful model 선택
  • better features 주입
  • constraints 줄이기
more powerful model 선택하도록 decisiontreeregressor로 training
from sklearn.tree import DecisionTreeRegressortree_reg = DecisionTreeRegressor()tree_reg.fit(housing_prepared, housing_labels)
housing_predictions = tree_reg.predict(housing_prepared)tree_mse = mean_squared_error(housing_labels, housing_predictions)tree_rmse = np.sqrt(tree_mse)tree_rmse
error가 0이 나옴. -> error가 0이 될 수 없기 때문에 overfitting된 것.

2) Better Evaluation Using Cross-Validation

DecisionTree model을 평가하는 방법 - train_test_split으로 training set를 더 작은 training set과 test set으로 나누어 training - K-fold cross validation
#K-fold cross-validationfrom sklearn.model_selection import cross_val_scorescores = cross_val_score(tree_reg, housing_prepared, housing_labels, scoring="neg_mean_squared_error", cv=10)tree_rmse_scores = np.sqrt(-scores)
#decisiontree scoredef display_scores(scores): print("Scores:", scores) print("Mean:", scores.mean()) print("Standard deviation:", scores.std())display_scores(tree_rmse_scores)
#linear regression scorelin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels, scoring="neg_mean_squared_error", cv=10)lin_rmse_scores = np.sqrt(-lin_scores)display_scores(lin_rmse_scores)
decisiontree보다 linear regression의 성능이 더 좋다.
#randomforestregressorfrom sklearn.ensemble import RandomForestRegressorforest_reg = RandomForestRegressor()forest_reg.fit(housing_prepared, housing_labels)housing_predictions = forest_reg.predict(housing_prepared)forest_mse = mean_squared_error(housing_labels, housing_predictions)forest_rmse= np.sqrt(forest_mse)forest_rmse
#randomforest scoreforest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels, scoring="neg_mean_squared_error", cv=10)forest_rmse_scores = np.sqrt(-forest_scores)display_scores(forest_rmse_scores)
randomeforest는 성능이 좋아보이지만 training score가 test score보다 매우 낮으므로 여전히 overfitting.
overfitting 해결 방법
  • model을 간단히
  • constraints
  • 더 많은 training data 모으기

6. Fine-tune your model.

1) Grid Search

탐색하려는 hyperparameter와 시도해볼 값을 지정하면 가능한 모든 combination of hyperparameter 에 대해 cross validation을 사용해 평가함.
#RandomForestRegressor에 대한 the best combination of hyperparameter 찾기from sklearn.model_selection import GridSearchCVparam_grid = [ {'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]}, {'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]}, ]forest_reg = RandomForestRegressor()grid_search = GridSearchCV(forest_reg, param_grid, cv=5, scoring='neg_mean_squared_error',return_train_score=True)grid_search.fit(housing_prepared, housing_labels)
grid_search.best_params_
grid_search.best_estimator_
#cvres = grid_search.cv_results#for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):# print(np.sqrt(-mean_score), params)

2) Randomized Search

비교적 적은 수이면 grid search 사용 괜찮으나 hyperparameter의 search space가 커지면 RandomizedSearchCV를 사용하는 것이 좋음. -> 반복횟수를 설정하면 hyperparameter가 각기 다른 값을 탐색한다는 장점 -> 반복횟수 조절만으로 컴퓨팅 자원 제어한다는 장점

3) Ensemble Methods

to combine the models that perform best.

4) Analyze the Best Models and Their Errors

#각 feature의 상대적인 중요도feature_importances = grid_search.best_estimator_.feature_importances_feature_importances
extra_attribs = ["rooms_per_hhold", "pop_per_hhold", "bedrooms_per_room"]cat_encoder = full_pipeline.named_transformers_["cat"]cat_one_hot_attribs = list(cat_encoder.categories_[0])attributes = num_attribs + extra_attribs + cat_one_hot_attribssorted(zip(feature_importances, attributes), reverse=True)
위를 바탕으로 덜 중요한 feature를 제거할 수 있음.

5) Evaluate Your System on the Test Set

#test set에서 predictor와 lable을 얻은 후 full_pipeline실행final_model = grid_search.best_estimator_X_test = strat_test_set.drop("median_house_value", axis=1)y_test = strat_test_set["median_house_value"].copy()X_test_prepared = full_pipeline.transform(X_test)final_predictions = final_model.predict(X_test_prepared)#test set에서 final model 평가final_mse = mean_squared_error(y_test, final_predictions)final_rmse = np.sqrt(final_mse)
from scipy import statsconfidence = 0.95squared_errors = (final_predictions - y_test) ** 2np.sqrt(stats.t.interval(confidence, len(squared_errors) - 1, loc=squared_errors.mean(), scale=stats.sem(squared_errors)))

7. Present your solution.


8. Launch, monitor, and maintain your system.