반응형

요즘 LLM 인공지능으로 세상이 또 하나의 변화에 직면한 것으로 보인다. 
그 중에서 가장 앞선 곳이 OpenAI라고 할 수 있다. 

AI의 구조에 대해 좀 더 빠르게 알아보는 것이 필요한 시점이라 생각한다.

1. AI 프로젝트 시작하기

요즘 ChatGPT로 촉발된 LLM(Large Language Model)이 폭발적으로 성장하고 있다.

이로 인해 많은 사람들이 인공지능에 대해 정말 많은 관심을 갖게 되었다.

파이썬은 그 여정에 있어서 강력한 동반자가 될 것이라고 생각한다.
왜냐하면 대부분의 인공지능 라이브러리를 파이썬에서 지원하고 있고, 배우기 쉽고 사용하기 편한 파이썬 언어가 인공지능 분야에서는 대세라고 생각하기 때문이다.

 

머신 러닝 라이브러리 소개

Scikit-Learn

Scikit-Learn은 사용하기 매우 쉽지만, 많은 머신 러닝 알고리즘을 효율적으로 구현하므로 머신 러닝을 배우기에 좋은 출발점이 된다.
이것은 2007년 David Cournapeau에 의해 만들어졌으며, 현재는 프랑스 컴퓨터 과학 및 자동화 연구소(Inria)의 연구팀이 주도적으로 이끌고 있다.

TensorFlow

TensorFlow는 분산 수치 계산을 위한 좀 더 복잡한 라이브러리다.
이것은 수백 개의 멀티-GPU(그래픽 처리 장치) 서버에 걸쳐 계산을 분산시켜 매우 큰 신경망을 효율적으로 훈련하고 실행할 수 있게 만들어준다.
TensorFlow(TF)는 Google에서 만들어졌으며, 많은 대규모 머신 러닝 애플리케이션을 지원한다.
2015년 11월에 오픈 소스로 공개되었으며, 2.0 버전은 2019년 9월에 출시되었다.

Keras

Keras는 신경망을 훈련하고 실행하기 매우 간단하게 만드는 고수준의 딥러닝 API이다.
Keras는 TensorFlow와 함께 번들로 제공되며, 모든 집약적인 계산을 위해 TensorFlow에 의존한다.

 

데이터 수집 및 처리

모든 AI 프로젝트의 시작점은 데이터 수집이다.
파이썬은 데이터 수집과 처리를 위한 훌륭한 라이브러리들을 제공한다.
pandas는 데이터 분석을 위한 필수 라이브러리이며, numpy는 수치 계산을 위한 강력한 도구다.
scikit-learn은 데이터 전처리와 모델링을 위한 간편한 기능들을 제공한다.
이 라이브러리들을 사용하여 데이터를 수집하고, 정제하며, 유용한 특성을 추출하는 작업을 진행한다.

첫 번째 머신러닝 모델 구축

데이터가 준비되었다면, 간단한 머신러닝 모델을 구축할 차례다.
scikit-learn의 분류기나 회귀 모델을 사용해보자.
예를 들어, 붓꽃(Iris) 데이터 세트를 사용하여 각 붓꽃의 종류를 분류하는 모델을 만들 수 있다.
이 과정에서 모델을 훈련시키고, 검증하며, 성능을 평가하는 방법을 배울 수 있다.

 

2. 파이썬으로 복잡한 AI 문제 해결하기

딥러닝 입문

TensorFlow나 PyTorch와 같은 프레임워크를 사용하여 딥러닝 모델을 구축하는 방법을 배워보자.
이러한 프레임워크는 복잡한 신경망을 쉽게 설계하고 학습시킬 수 있게 해준다.
간단한 이미지 분류부터 시작하여 점차 복잡한 문제로 나아가자.

사례 연구

실제로 파이썬을 사용하여 해결된 복잡한 AI 문제들을 살펴보는 것도 매우 유익하다.
Google의 AlphaGo부터 자율 주행 자동차에 이르기까지, 파이썬은 다양한 혁신적인 프로젝트에 사용되었다.

3. 파이썬 AI 리소스와 커뮤니티

학습 리소스

Coursera’나 ‘edX’와 같은 온라인 학습 플랫폼에서는 파이썬과 AI 관련 강좌를 제공한다.
또한 ‘GitHub’에는 수많은 오픈소스 프로젝트가 있어 실제 코드를 살펴보고 학습할 수 있는 기회를 제공한다.

커뮤니티 참여

Stack Overflow’, ‘Reddit’, ‘Kaggle’과 같은 플랫폼에서는 전 세계의 개발자들과 지식을 공유하고 문제를 해결할 수 있다.
또한, 파이썬과 AI 관련 컨퍼런스나 워크샵에 참여하여 네트워킹을 할 수 있다.

최신 동향 유지

AI 분야는 빠르게 발전하고 있다.
arXiv’, ‘Google Scholar’ 등의 리소스를 통해 최신 연구를 접하고, ‘Medium’이나 ‘Towards Data Science’와 같은 블로그를 통해 새로운 트렌드를 확인하도록 하자.

반응형
반응형

머신러닝 프로젝트 실행(6~7단계)


머신러닝 프로젝트 실행 순서는 

1. 문제를 정의하고 전체 그림 바라보기

2. 데이터 얻기

3. 인사이트를 찾기 위해 데이터 탐색하기

4. 기본 데이터 패턴을 머신러닝 알고리즘에 더 잘 노출할 수 있도록 데이터 준비하기

5. 다양한 모델을 탐색하고 그 중 가장 좋은 모델을 찾기

6. 모델을 알맞게 튜닝하고 멋진 솔루션으로 통합하기

7. 시스템 런칭, 모니터링과 유지하기

입니다.


지금까지, 1~5단계까지 살펴보았습니다. 이제 2단계만 살펴보면 마무리 될 것 같습니다. 


먼저, 

6. 모델을 알맞게 튜닝하고 멋진 솔루션으로 통합하기


이제 유망한 모델들을 가졌다고 가정해 봅시다. 

그럼, 이 모델들을 튜닝하는 것이 필요합니다. 

실행할 수 있는 몇가지 방법을 살펴보도록 하겠습니다.


그리드 서치(Grid Search)


모델 튜닝을 수행하는 한 가지 방법은 하이퍼파라미터 값들의 좋은 조합을 찾아낼 때까지, 수동으로 하이퍼파라미터(hyperparameters)를 사용하는 것입니다. 

이것은 매우 지루한 작업이 될 것이고, 많은 조합을 탐색할만한 시간을 갖고 있지 않을 수도 있습니다.

그 대신에, 사이킷런(Scikit-Learn)의 GridSearchCV로 탐색을 하도록 할 수 있습니다. 

해야할 일 전부는 어떤 하이퍼파라미터를 실험하고 싶은지, 어떤 값들을 시험해 보아야 하는지를 알려주는 것입니다. 

그러면, 교차검증(cross-validation)을 사용해, 하이퍼파라미터 값들의 모든 가능한 조합들을 평가할 것입니다. 

예를 들어, 다음의 코드는 RnadomForestRegreesor를 위해 하이퍼파라미터 값들에 대한 최상의 조합을 검색합니다. 

>>> from sklearn.model_selection import GridSearchCV

>>> param_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')

>>> grid_search.fit(housing_prepared, housing_labels)


팁) 하이퍼파라미터가 어떤 값을 가져야 할지 알 수 없을 때, 간단한 접근법은 연속적으로 10의 파워를 시도해 보는 것입니다. (또는 더 세분화된 탐색을 원한다면, 더 작은 숫자로 시도: n_estimators 하이퍼파라미터를 가진 위 예에서 보듯이)


위 param_grid는 사이킷런에게 처음에 n_estimators의 모든 3×4 = 12개의 조합과 첫번째 dict에서 특정한 max_features 하이퍼파라미터 값들을 평가하도록 알려줍니다. 

그 다음에 두번째 dict인 모든 2×3 = 6개의 하이퍼파라미터 값들의 조합을 시도합니다. 

하지만, 이번에는 bootstrap 하이퍼파라미터는 True(이 하이퍼파라미터의 기본값이 True임) 대신에 False를 설정합니다.

전체적으로, 그리드 서치(grid search)는 RandomForestRegressor 하이퍼파라미터 값들의 12+6 =18개 조합들을 탐색할 것입니다. 

그리고 각 모델을 5번씩(왜냐하면 five-fold 교차검증을 사용하기 때문) 훈련시킬 것입니다. 

달리 말하자면 전체적으로, 18×5 = 90번의 훈련 라운드가 될 것입니다. 

아주 많은 시간이 걸리겠지만, 아래와 같이 최상의 파라미터 조합을 얻게 될 것입니다.

>>> grid_search.best_params_

{'max_features': 6, 'n_estimators': 30}


팁) n_estimators의 최대값이 30으로 평가되었습니다. 점수가 지속적으로 향상될 수도 있기 때문에, 더 높은 값도 평가해 보아야 할 것입니다.


직접 최상의 평가자(estimator)를 얻을 수도 있습니다.

>>> grid_search.best_estimator_

RandomForestRegressor(bootstrap=True, criterion='mse', max_depth=None,

max_feature=6, max_leaf_nodes=None, min_samples_leaf=1,

min_samples_split=2, min_weight_fraction_leaf=0.0,

n_estimators=30, n_jobs=1, oob_score=False, random_state=None,

verbose=0, warm_start=False)


론 평가 점수들도 이용할 수 있습니다.

>>> cvres = grid_search.cv_results_

... for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):

...        print(np.sqrt(-mean_score), params)

...

64912.0351358 {'max_features': 2, 'n_estimators': 3}

55535.2786524 {'max_features': 2, 'n_estimators': 10}

52940.2696165 {'max_features': 2, 'n_estimators': 30}

60384.0908354 {'max_features': 4, 'n_estimators': 3}

52709.9199934 {'max_features': 4, 'n_estimators': 10}

50503.5985321 {'max_features': 4, 'n_estimators': 30}

59058.1153485 {'max_features': 6, 'n_estimators': 3}

52172.0292957 {'max_features': 6, 'n_estimators': 10}

49958.9555932 {'max_features': 6, 'n_estimators': 30}

59122.260006 {'max_features': 8, 'n_estimators': 3}

52441.5896087 {'max_features': 8, 'n_estimators': 10}

50041.4899416 {'max_features': 8, 'n_estimators': 30}

62371.1221202 {'bootstrap': False, 'max_features': 2, 'n_estimators': 3}

54572.2557534 {'bootstrap': False, 'max_features': 2, 'n_estimators': 10}

59634.0533132 {'bootstrap': False, 'max_features': 3, 'n_estimators': 3}

52456.0883904 {'bootstrap': False, 'max_features': 3, 'n_estimators': 10}

58825.665239 {'bootstrap': False, 'max_features': 4, 'n_estimators': 3}

52012.9945396 {'bootstrap': False, 'max_features': 4, 'n_estimators': 10}


위 예에서, max_features 하이퍼파라미터를 6으로, n_estimators 하이퍼파라미터를 30으로 설정함으로써 최상의 해결책을 확보할 수 있습니다. 

이 조합의 RMSE 점수는 49,959입니다. 

기본 하이퍼파라미터 값들(점수가 52,634)을 사용한 경우보다 더 좋은 점수를 얻었기 때문에 약간 더 좋아졌습니다. 

성공적으로 최상의 모델로 잘 튜닝했습니다!


팁) 하이퍼파라미터로 데이터 준비 단계 중 일부를 다룰 수 있다는 것을 잊지 마세요. 예를 들어, 그리드 서치(grid search)는 확신할 수 없는 피쳐(feature)를 추가하는 것과는 상관없이 자동적으로 찾아낼 것입니다. 자동으로 간단히 아웃라이어 핸들링, 누락된 피쳐들, 피쳐 선택 등에 대한 최상의 방법을 찾을 수 있도록 사용될 수 있을 것입니다. 


무작위 서치(Randomized Search)

그리드 서치(grid search) 접근법은 앞의 예처럼, 상대적으로 적은 조합을 탐색할 때 좋습니다. 

하지만, 하이퍼파라미터 서치 스페이스가 클때는, 그리드 서치 대신에 RandomizedSearchCV를 사용하는 것을 더 선호합니다. 

이 클래스는 GridSearchCV 클래스와 매우 유사한 방법으로 사용할 수 있습니다. 

하지만 모든 가능한 조합들을 시도하는 대신에, 매 반복시마다 각 하이퍼파라미터에 대해 랜덤한 값을 선택함으로써 주어진 숫자만큼 무작위 조합에 대해 평가합니다. 

이 접근법은 두가지 주요 혜택이 있습니다.

  • 만약 1,000회 반복하도록 무작위 서치를 실행한다면, 이 접근법은 각각의 하이퍼파라미터에 대해 1,000개의 다른 값들을 탐색할 것입니다. (그리드 서치 접근법에서는 각각의 하이퍼파라미터에 대해 단지 몇개의 값들을 탐색)

  • 단히 반복할 숫자를 설정함으로써, 하이퍼파라미터 검색에 할당할 컴퓨팅 자원을 더 잘 컨트럴할 수 있습니다. 


앙상블 메서드(Ensemble Methods)

시스템을 튜닝하기 위한 또 다른 방법은 가잘 잘 수행할 수 있는 모델들을 결합시켜 보는 것입니다. 

그 그룹(또는 "앙상블")은 최상의 개별 모델보다 더 잘 수행할 것입니다(랜덤 포레스트가 의지하는 개별 결정 트리 보다 랜덤 포레스트가 더 잘 수행하는 것과 같음). 

특히, 개별 모델이 매우 다른 형태의 오류를 만드는 경우 더 그렇습니다. 


최고의 모델과 그 모델의 에러 분석하기

가장 좋은 모델을 검사하여 문제에 대한 좋은 통찰을 얻을 수 있습니다. 

예를 들어, RandomForestRegressor은 정확한 예측을 하기 위해, 각 속성의 상대적 중요성을 나타낼 수 있습니다:

>>> feature_importances = grid_search.best_estimator_.feature_importances_

>>> feature_importances

array([  7.14156423e-02,   6.76139189e-02,   4.44260894e-02,

1.66308583e-02,  1.66076861e-02,   1.82402545e-02,

1.63458761e-02,   3.26497987e-01,   6.04365775e-02,

1.13055290e-01,   7.79324766e-02,   1.12166442e-02,

1.53344918e-01,   8.41308969e-05,   2.68483884e-03,

3.46681181e-03])


해당 속성의 이름 옆에 중요도 점수를 표시합시다:


>>> extra_attrivs = ["rooms_per_hhold", "pop_per_hhold", "bedrooms_per_room"]

>>> cat_one_hot_attribs = list(encoder.classes_)

>>> attributes = num_attribs + extra_attribs + cat_one_hot_attribs

>>> sorted(zip(feature_importances, attributes), reverse=True)

[(0.32649798665134971, 'median_income'),

(0.15334491760305854, 'INLAND'),

(0.11305529021187399, 'pop_per_hhold'),

(0.07793247662544775, 'bedrooms_per_room'),

(0.071415642259275158, 'longitude'),

(0.067613918945568688, 'latitude'),

(0.060436577499703222, 'rooms_per_hhold'),

(0.04442608939578685, 'housing_median_age'),

(0.018240254462909437, 'population'),

(0.01663085833886218, 'total_rooms'),

(0.016607686091288865, 'total_bedrooms'),

(0.016345876147580776, 'households'),

(0.011216644219017424, '<1H OCEAN'),

(0.0034668118081117387, 'NEAR OCEAN'),

(0.0026848388432755429, 'NEAR BAY'),

(8.4130896890070617e-05, 'ISLAND')


이 정보를 가지고, 유용하지 않은 피쳐들(features) 일부를 탈락시키고 싶을 수도 있습니다(예,. 분명히 하나의 ocean_proximity 범주만이 정말 유용합니다. 그래서 다른 것들에 대한 탈락을 시도할 수 있습니다).

또한, 시스템에서 발생시키는 특정 에러를 살펴보아야만 합니다. 

그런 다음, 발생 원인을 이해하도록 해야 하고, 그 문제를 어떻게 고칠 수 있는지도 이해해야 합니다(다른 피쳐들을 추가하거나 반대로 불필요한 피쳐들을 제거하고, 아웃라이어를 클리닝 하는 등). 


테스트 셋에서 시스템 평가하기

잠시동안 모델을 조정한 후에, 결국 효율적으로 잘 수행하는 시스템을 갖게 되었습니다. 

이제 최종 모델을 테스트 셋에서 평가해 볼 시간입니다. 

이 프로세스에 있어 특별한 것은 없습니다; 단지 테스트 셋에서 예측변수(predictors)와 레이블을 가져와, 데이터를 변환(fit_transform()이 아니라 transform()을 호출!)하기 위해 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)

>>> final_mse = mean_squared_error(y_test, final_predictions)

>>> final_rmse = np.sqrt(final_mse) 

많은 하이퍼파라미터를 튜닝했다면, 성능은 보통 교차 검증(cross-validation)을 사용해 측정한 것보다 조금 나쁠 겁니다

(왜냐하면, 검증 데이터에서 잘 수행되도록 미세 조정되었기 때문에, 알려지지 않은 데이터셋에서는 잘 수행되지 않을 것입니다). 

이 예에서는 그렇지 않습니다만, 이런 경우가 생기면 테스트 셋에서 숫자가 잘 나올 수 있도록 하이퍼파라미터를 조정하는 유혹에 빠지면 안됩니다; 그 개선은 새로운 데이터에 일반화될 것 같지 않기 때문입니다.

이제 프로젝트가 시작되는 시점이 되었습니다: 해결책을 제시하는 것(학습한 것을 강조 표시하고, 무엇이 작동되고 무엇이 안되는지, 어떤 가정들이 만들어 졌는지, 그리고 이 시스템의 한계는 무엇인지), 모든 것을 문서화하고, 분명한 시각화와 쉽게 기억할 수 있는 문구를 가진 멋진 프리젠테이션을 만드는 것이 필요합니다(예,. "중앙 소득은 주택 가격의 가장 중요한 예측 변수 입니다").


7. 시스템 런칭, 모니터링과 유지하

이제 제품화를 위한 솔루션 준비가 필요합니다. 

특히, 제품을 가동함으로써 시스템에 데이터 소스를 입력하고 테스트를 작성하기 위한 준비가 필요합니다.

또한, 시스템을 정기적으로 실제 사용중에 점검할 수 있는 모니터링 코드를 작성하는 것도 필요합니다. 

문제가 생기면 경고도 날려줘야 합니다. 

이것은 갑작스런 작동중단 뿐 아니라, 성능 저하를 잡아내는 데 있어 중요합니다. 

모델은 정기적으로 새로운 데이터로 훈련되지 않으면, 시간이 지남에 따라 모델의 데이터가 "망가지는" 경향이 있기 때문에 매우 일반적입니다.


시스템의 성능을 평가하려면 시스템의 예측을 샘플링하고 그것들을 평가해야 합니다. 이것은 일반적으로 사람의 분석을 요구합니다. 이 분석가들은 현장 전문가일 수도 있고, 크라우드소싱 플랫폼의 작업자일 수도 있습니다(Amazon Mechanical Turk 또는 CrowdFlower 같은). 어느 쪽이든, 사람의 평가 파이프라인을 시스템에 연결해야 합니다. 

또한, 시스템의 입력 데이터 품질을 평가해야 합니다. 

때때로 나쁜 품질 시그널(예., 오작동하는 센서가 무작위 값들을 보내거나, 다른 팀의 결과가 부실해지거나)때문에, 성능이 약간씩 떨어질 것입니다. 

하지만, 시스템 성능 저하에 따른 경고를 받기까지는 딜레이 시간이 걸리 수 있습니다. 

만약 시스템의 입력을 모니터하고 있다면, 이 경고를 더 일찍 잡아낼 수 있습니다. 

특히 입력 모니터링은 온라인 학습 시스템에서 중요합니다.


마지막으로 말할 것은, 일반적으로 새로운 데이터를 가지고 정기적으로 모델을 훈련시키는 것을 원할 것이라는 것입니다.

가능한 한 이 프로세스를 자동화해야 합니다. 

그렇지 않으면, (적어도) 6개월마다 시스템을 고칠 가능성이 큽니다. 

그리고 시스템 성능은 시간이 지남에 따라 크게 변동될 수 있습니다. 

만약 온라인 학습 시스템이라면, 일정한 간격으로 상태 시냅샷을 저장해야만 할 것입니다. 

그렇게 해서, 쉽게 이전의 작동 상태로 되돌아갈 수 있습니다. 


여기까지가 예제를 가지고 학습해 본 머신러닝 프로젝트 실행에 대한 전체 프로세스였습니다. 

여러 번 읽어보고 익혀야 이해가 될 것 같네요. 

앞으로 저도 지금까지 설명한 절차대로 http://kaggle.com과 같은 사이트에서 실습을 진행해 보고 싶습니다.



머신러닝 프로젝트 실행-1

(1~2단계: 1. 문제정의하고 전체 그림 바라보기 / 2. 데이터 얻기바로가기 


머신러닝 프로젝트 실행-2

(3단계: 3. 인사이트를 찾기 위해 데이터 탐색하기바로가기 


머신러닝 프로젝트 실행-3

(4단계: 4. 기본 데이터 패턴을 머신러닝 알고리즘에 더 잘 노출시킬 수 있도록 데이터 준비하기바로가기


머신러닝 프로젝트 실행-4

(5단계: 5. 다양한 모델을 탐색하고 그 중 가장 좋은 모델 찾기바로가기


참고)'Hands-On Machine Learning with Scikit-Learn and TensorFlowchapter 2' 

주피터 노트북에서 볼 수 있는 전체 코드 얻기

반응형
반응형

이번에는 머신러닝 프로젝트 4단계에 이어, 5단계를 살펴보도록 하겠습니다.


5. 다양한 모델을 탐색하고 그 중 가장 좋은 모델 찾기

지금까지 문제를 정의하고, 데이터를 얻어서 탐색해 보았습니다. 

그리고 트레이닝 셋과 테스트 셋을 샘플링하고, 자동적으로 머신러닝 알고리즘을 위해 클리닝해서 데이터를 준비하기 위해 변형 파이프라인을 작성했습니다. 

이제 머신러닝 모델을 선택해서 트레이닝시킬 준비가 되었습니다.


트레이닝 셋에서 훈련하고 평가하기

좋은 소식은 이전 1~4단계 덕분에, 이제 생각했던 것보다 상황이 훨씬 간단하게 진행될 것이라는 것입니다. 

우선 선형 회귀 모델을 트레이닝해 봅시다.

>>> from sklearn.linear_model import LinearRegression

>>> lin_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:\t", lin_reg.predict(some_data_prepared))

Predctions:    [    303104.    44800.    308928.    294208.    368704. ]

>>> print("Labels:\t\t", list(some_labels))

Labels:        [359400.0,  69700.0,  302100.0,  301300.0,  351900.0]


예측이 아주 정확하지는 않지만 작동합니다

(두번째 예측이 50% 이상 차이가 있습니다!). 

사이킷런(Scikit-Learn)의 mean_squared_error 함수를 사용해서 전체 트레이닝 셋에 대한 이 회귀 모델의 RMSE를 측정해 봅시다.        

>>> from sklearn.metrics import mean_squared_error>>> housing_predictions = lin_reg.predict(housing_prepared)>>> lin_mse = mean_sqared_error(housing_labels, housing_predictions)
>>> lin_rmse = np.sqrt(lin_mse)
>>> lin_rmse
68628.413493824875

이제, 좀 나아졌습니다. 
하지만 아직 좋은 점수를 받을 정도는 아닙니다: 가장 큰 지구(district)의 median_housing_values의 범위는 120,000 달러에서 265,000달러 사이입니다. 
따라서 68,628달러의 전형적인 예측 에러는 아주 만족스럽지 못합니다.
이것이 트레이닝 데이터의 과소적합(underfitting)된 모델의 사례입니다. 
이런 일이 일어나면, 훌륭한 예측을 만들어 내기 위해 피처들(features)이 충분한 정보를 제공하지 않았다는 것 또는 이 모델이 충분히 파워풀 하지 않다는 것을 의미할 수 있습니다. 
앞의 단계에서 보았듯이, 과소적합(underfitting)을 수정하기 위한 주요 방법은 더욱 강력한 모델을 선택하고, 더 좋은 피쳐들(features)을 가진 트레이닝 알고리즘을 먹이는 것입니다. 또는 이 모델에 대한 제약을 줄이는 것입니다. 이 모델은 정규화되지 않았기 때문에, 이 규칙들은 마지막 옵션에서 제외됩니다. 더 많은 피쳐들(features)을 추가하는 것(예를 들어, 인구의 로그)을 시도해 볼 수 있습니다. 하지만 먼저 보다 복잡한 모델을 시도해 보도록 합시다.
DecisionTreeRegressor을 훈련시켜 봅시다. 
이것은 데이터에서 복잡한 비선형 관계를 찾아낼 수 있는 강력한 모델입니다. 
코드가 이제 친숙해 보여야 할 것입니다:

>>> from sklearn.tree import DecisionTreeRegressor
>>> tree_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
0.0

잠깐, 뭘까요? 아무런 에러도 없었습니다. 정말 이 모델이 완벽한 걸까요? 
물론, 이 모델이 이 데이터에 과적합(overfitting)했을 가능성이 훨씬 높습니다. 
어떻게 확신할 수 있을까요? 
앞에서 보았듯이, 만족스러운 모델을 런칭할 준비가 될 때까지 테스트 셋을 만지는 것을 원하지 않을 것입니다. 
그래서 트레이닝 셋 일부를 훈련용으로 사용하고, 일부는 모델 검증용으로 사용하는 것이 필요합니다.


교차검증(Cross-Validation)을 사용해 더 좋은 평가 만들기

결정트리(Decision Tree) 모델을 평가하기 위한 한가지 방법은 트레이닝 셋을 더 작은 트레이닝 셋과 검증 셋으로 구분하기 위해 train_test_split 함수를 사용하는 것일 겁니다. 그후 더 작은 트레이닝 셋을 모델을 훈련시키고 검증 셋에 대해 검증을 실시합니다. 약간의 작업이 있긴 하지만, 그다지 어렵지 않고 잘 작동할 것입니다.
훌륭한 대안은 사이킷런(Scikit-Learn)의 교차검증(cross-validation) 기능을 이용하는 것입니다. 
다음의 코드는 K-fold 교차검증(cross-validation)을 실행합니다: 무작위로 folds라 불리는 10개 단위의 서브셋으로 트레이닝 셋을 분리합니다. 
그 다음 결정트리(Decision Tree) 모델로 10번 훈련시키고 평가합니다. 
매번 평가를 위해 다른 fold를 골라내고 또 다른 9개 folds를 훈련시킵니다. 
그 결과는 10개의 평가 점수를 포함한 배열로 나타납니다.

>>> from sklearn.model_selection import cross_val_score
>>> scores = cross_val_score(tree_reg, housing_prepared, housing_labels, 
scoring="neg_mean_squared_error", cv=10)
>>> rmse_scores = np.sqrt(-scores)

(주의) 사이킷런(Scikit-Learn)의 교차검증(cross-validation) 기능은 코스트 함수(작을수록 더 좋은)가 아닌 유틸리티 함수(클수록 더 좋은)를 기대합니다. 
그래서 스코어링 함수는 실제로 MSE와 반대(앞의 코드처럼 계산된 이유-제곱근을 계산하기 전의 값)입니다. 

결과를 보도록 합시다:
>>> def display_scores(scores):
...            print("Scores:", scores)
...            print("Mean:", scores.mean())
...            print("Standard deviation:", scores.std())
...
>>> display_scores(tree_rmse_scores)
Scores: [  74678.4916885   64766.2398337    69632.86942005   69166.67693232
71486.76507766  73321.65695983   71860.04741226     71086.32691692
76934.2726093   69060.93319262]
Mean:  71199.4280043
Standard deviation: 3202.70522793

지금 결정트리(Decision Tree)가 앞에서 했던 것보다 좋아보이진 않습니다. 
사실, 선형 회귀 모델보다 더 나쁘게 수행하는 것처럼 보입니다! 
교차검증(cross-validation)이 당신 모델의 성능을 검증하는 것 뿐만 아니라 이 검증이 얼마나 정확한지 측정하는 것(예., 표준편차) 역시 수행하고 있다는 것에 유념하시기 바랍니다. 
이 결정트리(Decision Tree)는 정확히, 일반적으로 ±3,200의 편차를 갖는, 71,200의 점수를 받았습니다. 
하나의 검증 셋만을 사용한다면,  이런 정보를 가질 수 없습니다. 하지만, 교차검증(cross-validation)은 몇 번에 걸쳐 모델을 훈련시키는 비용이 따르기 때문에 항상 가능하지는 않습니다. 
선형 회귀 모델을 확인해 보기 위해 동일한 점수를 계산해 보도록 합시다:

>>> lin_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)
Scores: [  70423.5893262   65804.84913139   66620.84314068   72510.11362141
66414.74423281   71958.89083606   67624.90198297    67825.36117664
72512.36533141    68028.11688067]
Mean:  68972.377566
Standard deviation: 2493.98819069

맞습니다: 결정트리(Decision Tree) 모델이 과적합(overfitting)되었습니다. 
그래서 슬프게도 선형 회귀 모델보다 안좋은 성능을 발휘합니다. 
이제 마지막 남은 모델을 시도해 보도록 합시다: RandomForestRegressor. 랜덤 포레스트(Random Forests)는 예측값을 평균화하는 대신 피처들(features)의 무작위 서브셋을 많은 결정트리(Decision Trees)로 훈련시켜 작동합니다.  
많은 다른 모델들의 최고 위에 모델을 세우는 것을 앙상블 학습(Ensemble Learning)이라 부릅니다.  ML 알고리즘을 더욱 발전시키기 위한 좋은 방법입니다. 
다른 모델들과 본질적으로 동일하기 때문에, 코드의 대부분을 넘어갈 것입니다:

>>> from sklearn.ensemble import RandomForestRegressor
>>> forest_reg = RandomForestRegressor()
>>> forest_reg.fit(housing_prepared, housing_labels)
>>> [...]
>>> forest_rmse
22542.396440343684
>>> display_scores(forest_rmse_scores)
Scores: [  53789.2879722    50256.19806622   52521.55342602    53237.44937943
52428.82176158    55854.61222549    52158.02291609    50093.66125649
53240.80406125   52761.50852822]
Mean:  52634.1919593
Standard deviation: 1576.20472269

이제 더 좋아졌습니다: 랜덤 포레스트(Random Forests)가 더 유망해 보입니다. 하지만, 검증셋보다 트레이닝 셋의 점수가 여전히 더 낮다는 것에 유념하시기 바랍니다. 
이것은 이 모델이 여전히 트레이닝 셋에 과적합(overfitting)되어 있다는 것을 의미합니다. 
과적합(overfitting)에 있어 가능한 해결책은 모델을 단순화하고, 제약을 가하거나(예, 정규화하는 것), 더 많은 훈련 데이터를 얻는 것입니다.  
하지만, 랜덤 포레스트(Random Forests)에 더 깊이 들어가기 전에, 하이퍼파라미터를 조율하는데 너무 많은 시간을 소비하지 않고, 다양한 범주의 머신러닝 알고리즘으로부터 많은 다른 모델들을 시도해 보아야 할 것입니다. 
목표는 몇 가지(2~5개의) 유망한 모델을 선정하는 것입니다.

5단계는 여기까지입니다. 

머신러닝 프로젝트 실행-1

(1~2단계: 1. 문제정의하고 전체 그림 바라보기 / 2. 데이터 얻기바로가기 


머신러닝 프로젝트 실행-2

(3단계: 3. 인사이트를 찾기 위해 데이터 탐색하기바로가기 


머신러닝 프로젝트 실행-3

(4단계: 4. 기본 데이터 패턴을 머신러닝 알고리즘에 더 잘 노출시킬 수 있도록 데이터 준비하기바로가기


참고)'Hands-On Machine Learning with Scikit-Learn and TensorFlowchapter 2' 

주피터 노트북에서 볼 수 있는 전체 코드 얻기


반응형
반응형

머신러닝 프로젝트 실행 1~3단계에 이어, 4단계를 정리하도록 하겠습니다.

4. 기본 데이터 패턴을 머신러닝 알고리즘에 더 잘 노출할 수 있도록 데이터 준비하기

머신러닝 알고리즘을 위한 데이터를 준비할 시간입니다. 이것을 수동으로 하는 대신에, 자동으로 생성할 함수들을 사용해야 합니다. 

그 이유는 다음과 같습니다.

  • 어떤 데이터셋이든(예, 다음 번에 새로운 데이터셋을 얻게 되었을 때), 이들 변환을 쉽게 재적용할 수 있도록 해줍니다.
  • 미래의 프로젝트에서 재사용할 수 있는 변환 함수 라이브러리를 만들 수 있습니다.
  • 이들 함수들을 알고리즘에 피딩하기 전에 새로운 데이터를 변환하기 위해 실제 사용하는 시스템에서 사용할 수 있습니다. 
  • 다양한 변환을 쉽게 시도하고 어떤 변환 조합이 가장 잘 동작하는지 알 수 있도록 해줍니다.
이제 트레이닝 셋을 클리닝하기 위해 되돌려 봅시다(다시 한번strat_train_set을 복사하면 됩니다). 그리고 불필요하게 예측변수와 목표 값들에 동일한 변환이 적용되기를 원하지 않기 때문에 예측변수와 레이블을 분리하도록 합시다.
(drop()이 데이터 복사본을 만들고, strat_train_set에는 영향을 주지 않는 것에 주의하시기 바랍니다) 

>>> housing = strat_train_set.drop("median_house_value", axis=1)
>>> housing_labels = strat_train_set["median_house_value"].copy()

데이터 클리닝

대부분의 머신러닝 알고리즘은 누락된 값이 있는 피처들(features)로는 작업할 수 없습니다. 따라서, 그것들을 다루기 위한 몇가지 함수들을 만들어 봅시다. 전 단계에서 total_bedrooms 속성에 누락된 값들이 있다는 것을 보았습니다. 이것을 고쳐보도록 합시다. 
다음의 3가지 옵션을 선택할 수 있습니다.

  • 상응하는 지구(districts)를 제거합니다.

  • 전체 속성을 제거합니다.

  • 값들을 특정 값으로 설정합니다(제로, 평균, 중앙값 등).
이것들을 DataFrame의 dropna(), drop(), 그리고 fillna() 메서드를 사용해 쉽게 처리할 수 있습니다.

>>> housing.dropna(subset=["total_bedrooms"]) # 옵션1
>>> housing.drop("total_bedrooms", axis=1) # 옵션2
>>> median = housing["total_bedrooms"].median()
>>> housing["total_bedrooms"].fillna(median) # 옵션3

만약 옵션3을 선택한다면, 트레이닝 셋에 대한 중앙값을 계산해야만 합니다. 그리고 트레이닝 셋의 누락된 값들에 이것을 적용해야 합니다. 
하지만, 위 코드처럼 계산했던 중앙값을 저장하는 것을 잊지 말아야 합니다. 
나중에 시스템을 평가하고 싶을 때, 테스트 셋에서 누락된 값들을 대체하는 것이 필요할 것입니다. 그리고, 시스템을 운영한 후에는 신규 데이터에서 누락된 값들을 즉석에서 대체해야 합니다.

>>> from sklearn.preprocessing import Imputer
>>> imputer = Imputer(strategy="median")

중앙값은 수치 속성들에 대해서만 계산될 수 있기 때문에, 텍스트 속성의 ocean_proximity를 제외한 데이터의 복사본을 생성하는 것이 필요합니다.

>>> housing_num = housing.drop("ocean_proximity", axis=1)

이제 fit() 메서드를 사용해 트레이닝 데이터에 imputer 인스턴스를 적용할 수 있습니다.

>>> imputer.fit(housing_num)

imputer는 간단하게 각 속성의 중앙값을 계산하고, 그 결과를 statistics_ 인스턴스 변수에 저장합니다. 
total_bedrooms 속성만이 누락된 값이 있지만, 이 시스템이 실제 운용되었을 때 신규 데이터에 어떤 누락된 값들이 있을지 확신할 수 없을 것입니다. 
그래서, 모든 수치 속성들에 대해 imputer를 적용하는 것이 더 안전합니다.

>>> imputer.statistics_
array([ -118.51 , 34.26 , 29. , 2119. , 433. , 1164. , 408. , 3.5414])
>>> housing_nim.median().values
array([ -118.51 , 34.26 , 29. , 2119. , 433. , 1164. , 408. , 3.5414]) 

이제 학습된 중앙값으로 누락된 값들을 대체함으로써 트레이닝 셋을 변환하기 위해 "훈련된" imputer를 이용할 수 있습니다. 

>>> X = imputer.transform(housing_num)

결과물은 변환된 피쳐들(features)을 포함한 평이한 넘파이(Numpy) 배열입니다. 
판다스(Pandas) DataFrame으로 다시 넣고 싶다면, 간단히 처리할 수 있습니다.

>>> housing_tr = pd.DataFrame(X, columns=housing_num.columns)


텍스트 다루기와 범주 속성들

앞에서 범주 속성인 ocean_proximity를 제외했습니다. 
그 이유는 텍스트 속성이기 때문에 중앙값을 계산할 수 없기 때문입니다. 
대부분의 머신러닝 알고리즘은 숫자를 가지고 작업하는 것을 선호합니다. 
그렇기 때문에 이들 텍스트 라벨을 숫자로 변환해 봅시다.
사이킷 런(Scikit-Learn)은 이 작업에 필요한 LabelEncoder라 불리는 변환기를 제공합니다.

>>> from sklearn.preprocessing import LabelEncoder
>>> encoder = LabelEncoder()
>>> housing_cat = housing["ocean_proximity"]
>>> housing_cat_encoded = encoder.fit_transform(housing_cat)
>>> housing_cat_encoded
array([1, 1, 4, ..., 1, 0, 3])

이러면 더 좋아집니다: 이제 어떤 ML 알고리즘에서도 이 숫자 데이터를 사용할 수 있습니다. 
이 인코더가 classes_ 속성을 사용하여 학습한 매핑을 볼 수 있습니다("<1H OCEAN"이 0에 매핑되었고, "INLAND"가 1에 매핑되었습니다).

>>> print(encoder.classes_)
['<1H OCEAN' 'INLAND' 'ISLAND' 'NEAR BAY' 'NEAR OCEAN']

위 인코더로 처리한 데이터의 한가지 이슈는 ML 알고리즘이 두개의 근접한 값들이 거리가 있는 두개의 값들보다 더 유사하다고 가정한다는 것입니다. 
분명히 이것은 그런 경우가 아닌데 말입니다(예를 들어, 범주 0과 4가 범주 0과 1보다 더 유사합니다). 
이 이슈를 수정하기 위한, 일반적인 솔루션은 각 범주에 대한 하나의 바이너리 속성을 생성하는 것입니다: 범주가 "<1H OCEAN"일 때 하나의 속성은 1과 같습니다(그렇지 않으면 0). 범주가 "INLAND"일 때 또 다른 속성이 1과 같습니다(그렇지 않으면 0) 등등. 
이것을 원-핫 인코딩이라 부릅니다. 범주들을 원-핫 벡터들로 인코딩합시다. 
fit_transform()은 2D 배열을 기대하지만, housing_cat_encoded는 1D 배열이라는 것을 주의하시기 바랍니다. 
그래서 이것을 재구성하는 것이 필요합니다.

>>> from sklearn.preprocessing import OneHotEncoder
>>> encoder = OneHotEncoder()
>>> housing_cat_1hot = encoder.fit_transform(housing_cat_encoded.reshape(-1,1))
>>> housing_cat_1hot
<16513x5 sparse matrix of type '<class 'numpy.float64'>'
        with 16513 stored elements in Compressed Sparse Row format>

산출물이 NumPy 배열이 아니라 SciPy 스파스(sparse) 매트릭스인 것에 유의하시기 바랍니다. 
이것은 수천 개의 범주들을 가진 범주 속성을 가질 때 매우 유용합니다. 
원-핫 인코딩 후, 수천개의 컬럼을 가진 매트릭스를 얻었습니다. 
그리고 그 매트릭스는 각 열마다 하나의 1을 가진 것 말고는 0으로 가득합니다. 엄청난 메모리를 0을 저장하는데 사용하는 것은 매우 비효율적입니다. 
그래서 대신 스파스(sparse) 매트릭스는 오직 0이 아닌 요소들의 위치만 저장합니다. 대개 일반적인 2D 배열처럼 사용할 수 있습니다. 하지만 정말 NumPy 배열로 전환하고 싶다면, toarray() 메서드를 호출하기만 하면 됩니다. 

>>> housing_cat_1hot.toarray()
array([[ 0.,  1.,  0.,  0.,  0.],
    [0.,  1.,  0.,  0.,  0.],  
    [0.,  0.,  0.,  0.,  1.], 
    [1.,  0.,  0.,  0.,  0.],  
    [0.,  0.,  0.,  1.,  0.]])

  
LabelBinarizer 클래스를 사용해서 (텍스트 범주에서 숫자 범주로 바꾸고, 숫자 범주에서 원-핫 벡터로 바꾸는) 두개의 변환을 한번에 적용할 수 있습니다. 

>>> from sklearn.preprocessing import LabelBinarizer
>>> encoder = LabelBinarizer()
>>> housing_cat_1hot = encoder.fit_transform(housing_cat)
>>> housing_cat_1hot
array([[ 0,  1,  0,  0,  0],
    [0,  1,  0,  0,  0],  
    [0,  0,  0,  0,  1], 
 ...,
    [0,  0,  0,  0,  1], 
    [1,  0,  0,  0,  0],  
    [0,  0,  0,  1,  0]])

기본적으로 고밀도 NumPy 배열을 돌려준다는 것에 유의하시기 바랍니다. 
sparse_output=True를 LabelBinarizer 컨스트럭터(constructor)를 전달함으로써 스파스(sparse) 매트릭스를 얻을 수 있습니다. 

사용자 정의 트랜스포머(Transformers)

사이킷런(Scikit-Learn)이 많은 유용한 트랜스포머(Transformers)를 제공하지만, 사용자 정의 클린업 또는 특정 속성들을 결합하는 것과 같은 작업을 위해 자신만의 트랜스포머를 작성하는 것이 필요할 것입니다. 
사이킷런(Scikit-Learn)의 기능들(pipelines과 같은)을 가지고 완벽하게 작동하는 자신만의 트랜스포머를 원할 수 있습니다. 
사이킷런(Scikit-Learn)이 덕 타이핑(상속이 아닌)에 의존하기 때문에, 클래스를 생성하고 3개의 메서드 구현하는 것이 필요한 전부입니다: fit(), transform(), 그리고 fit_transform(). 간단히 기본 클래스로써 TransformerMixin을 추가함으로써 무료로 하나를 얻을 수 있습니다. 
또한, 기본 클래스로 BaseEstimater를 추가한다면(컨스트럭터(constructor)에 *args와 *kargs를 피하세요), 자동 하이퍼파라미터를 조율하는데 유용한 두개의 특별 메서드(get_params()와 set_params())를 얻을 수 있습니다. 
예를 들어, 아래 코드는 앞에서 논의한 결합된 속성들을 추가하는 작은 트랜스포머(transformer) 클래스입니다. 

컴퓨터 프로그래밍 분야에서 덕 타이핑(duck typing)은 동적 타이핑의 한 종류로, 객체의 변수 및 메소드의 집합이 객체의 타입을 결정하는 것을 말합니다. 

>>> from sklearn.base import BaseEstimator, TransformerMixin
>>> rooms_ix, bedrooms_ix, population_ix, household_ix = 3,4,5,6
>>> class CombineAttributesAdder(BaseEstimator, TransformerMixin):
def __init__(self, add_bedrooms_per_room = True): # *args와 *kargs를 피하세요
self.add_bedrooms_per_room = add_bedrooms_per_room
def fit(self, X, y=None):
return self # 할 일은 없습니다
def transform(self, X, y=None):
rooms_per_household = X[:, rooms_ix] / X[:, household_ix]
population_per_household = X[:, population_ix] / X[:, household_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 = CombineAttributesAdder(add_bedrooms_per_room=False)
>>> housing_extra_attribs = attr_adder.transform(housing.values)

이 예에서, 트랜스포머(transformer)는 기본적으로 True를 설정한(흔히 민감한 기본값을 제공하는데 도움이 됨)하나의 하이퍼파라미터, add_bedrooms_per_room를 가지고 있습니다. 
이 하이퍼 파라미터는 이 속성을 추가하는 것이 머신러닝 알고리즘에 도움이 되는지 안되는지 쉽게 찾을 수 있도록 해줄 것입니다. 
더 일반적으로, 100% 확신할 수 없는 어떤 데이터를 준비하는 단계에서 점검하기 위한 하이퍼파라미터를 추가할 수 있습니다. 
이들 데이터의 준비 단계를 더 많이 자동화하고, 자동화를 시도할 수 있는 결합을 더 많이 할수록, 매우 좋은 결합을 발견할 가능성이 매우 높아질 것입니다(그리고 많은 시간을 절약하게 해 줄 것입니다).

피처(Feature) 스케일링(Scaling)

데이터에 적용이 필요한 가장 중요한 변환 중 하나는 피처(feature) 스케일링(scaling)입니다. 
몇 가지 예외가 있지만, 머신러닝 알고리즘은 입력 숫치 속성들이 매우 다른 스케일링을 가지면 잘 수행되지 않습니다. 
housing 데이터가 그런 경우입니다: 중간 소득이 0에서 15까지의 범위를 가지는 것에 비해, 전체 방수는 6에서 39,320까지의 범위를 가집니다. 목표 값의 스케일링은 일반적으로 필요하지 않다는 것에 유의하시기 바랍니다.
모든 속성들이 동일한 스케일을 갖도록 하는 두가지 일반적인 방법이 있습니다: min-max scaling과 standardization.
Min-max scaling(많은 사람들이 normalization이라 부릅니다)은 매우 간단합니다: 값들이 이동되어, 결국 0에서 1사의 범위에서 재스케일링 됩니다. 최소값을 뺀 값에, 최대값에서 최소값을 마이너스한 값을 나눔으로써 구합니다. 
사이킷런(Scikit-Learn)에서는 이를 위해 MinMaxScaler라는 트랜스포머를 제공합니다. 
어떤 이유로 0-1의 범위를 원하지 않을 때 범위를 변경할 수 있도록 feature_range라는 하이퍼트랜스포머를 갖습니다.

표준화(Standardization)는 전혀 다릅니다: 먼저 평균값을 구합니다(그래서 표준화된 값은 항상 제로 평균값을 갖습니다). 그런 다음 분산으로 나누어, 그 결과 분포가 단위 분산을 갖도록 합니다. 
min-max scaling과 달리, 표준화(Standardization)는 값을 특정 범위로 한정하지 않습니다. 
이것이 몇몇 알고리즘에서는 문제가 될 수도 있습니다(예를 들어, 뉴럴 네트워크는 흔히 입력 값의 범위를 0에서 1이라고 기대합니다). 하지만, 표준화(Standardization)는 특이값(outliers)에 의한 영향을 훨씬 덜 받습니다. 
예를 들어, 한 지구(district)의 중간 소득이 100과 같다고(실수로) 가정합시다. Min-max scaling은 모든 다른 값들이 0-15에서 0-0.15로 망가트립니다. 반면에 표준화(Standardization)는 별로 영향을 받지 않습니다. 
사이킷런(Scikit-Learn)은 표준화(Standardization)를 위해 StandardScaler라는 트랜스포머를 제공합니다.

변환 파이프라인(Pipeline)

보시다시피, 올바른 순서로 실행해야 하는 데이터 변환의 많은 단계가 있습니다. 
사이킷런(Scikit-Learn)은 그러한 일련의 변환을 도와줄 수 있는 파이프라인(Pipeline) 클래스를 제공합니다.
수치 속성들에 대한 작은 파이프라인 코드를 보시기 바랍니다:

>>> from sklearn.pipeline import Pipeline
>>> from sklearn.preprocessing import StandardScaler
>>> num_pipeline = Pipeline([
('imputer', Imputer(strategy="median")),
('attribs_adder', CombinedAttributesAdder()),
('std_scaler', StandardScaler()),
])
>>> housing_num_tr = num_pipeline.fit_transform(housing_num)

파이프라인(Pipeline) 생성자(constructor)는 일련의 단계를 정의하는 이름(name)/추정량(estimator) 쌍 리스트를 가집니다. 
마지막 추정량을 제외한 모든 것이 트랜스포머여야 합니다(예, 그것들은 fit_transform() 메서드를 가져야만 합니다). 
이름들(names)은 좋아하는 어떤 것으로도 정할 수 있습니다.
파이프라인의 fit() 메서드를 호출할 때, 마지막 추정량에 도달할 때까지, 파라미터로써 각 호출의 결과물을 다음 호출에 전달합니다. 
모든 트랜스포머에 대해 순차적으로 fit_transform()을 호출하며, 이를 위해서 fit() 메서드를 호출하기만 하면 됩니다.
파이프라인은 마지막 추정량으로써 동일한 메서드를 제공합니다. 마지막 추정량은 StandardScaler입니다. 
이것은 트랜스포머이기 때문에 파이프라인은 순차적으로 데이터에 모든 변환을 전달하는 transform() 메서드를 가집니다(또한 fit()과 함께 transform()을 호출하는 대신에 사용했던 fit_transform 메서드를 가집니다).
이제 수치 값들에 대한 파이프라인을 가지고 되었습니다. 그리고, LabelBinarizer를 범주 값들에 대해 적용하는 것이 필요합니다: 이러한 변환을 어떻게 단일 파이프라인에 결합시킬 수 있을까요? 사이킷런(Scikit-Learn)은 이것을 위해 FeatureUnion 클래스를 제공합니다. 변환 리스트를 제공하고(전체 변환 파이프라인이 될 수 있습니다), transform() 메서드가 호출되었을 때 각각의 변환에 대한 transform() 메서드가 병행으로 실행됩니다. 
결과물을 기다린 후, 그것들을 결합하고 결과값으로 돌려줍니다. 
수치와 범주 속성 양쪽을 핸들링하는 전체 파이프라인은 다음처럼 보여질 수 있습니다:

>>> from sklearn.pipeline import FeatureUnion
>>> num_attribs = list(housing_num)
>>> cat_attribs = ["ocean_proximity"]
>>> num_pipeline = Pipeline([
('selector', DataFrameSelector(num_attribs)),
('imputer', Imputer(strategy="median")),
('attribs_adder', CombinedAttributesAdder()),
('std_scaler', StandardScaler()),
])
>>> cat_pipeline = Pipeline([
('selector', DataFrameSelector(cat_attribs)),
('label_binarizer', LabelBinarizer()),
])
>>> full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline),
])

그리고 전체 파이프라인을 간단하기 실행할 수 있습니다:

>>> housing_prepared = full_pipeline.fit_transform(housing)
>>> housing_prepared
array([[ 0.73225807,  -0.67331551,  0.58426443,  ...,  0.           ,  0.          ,  0.           ],
 [-0.99102923,   1.63234656, -0.92655887,  ...,  0.           ,  0.          ,  0.           ],
 [...]
>>> housing_prepared.shape
(16513, 17)

각 서브 파이프라인은 선택기(selector) 파이프라인으로 시작합니다: 간단히 원하는 속성(수치 또는 범주)을 선택함으로써 데이터를 변환합니다. 
나머지를 버리고, 결과 DataFrame을 넘파이(NumPy) 배열로 전환합니다. 
사이킷런(Scikit-Learn)에서는 판다스(Pandas) DataFrame을 핸들링할 수 없기 때문에, 이 작업을 위해 간단한 사용자 정의 트랜스포머를 작성하는 것이 필요합니다.

>>> from sklearn.base import BaseEstimator, TransformerMixin
>>> class DataFrameSelector(BAseEstimator, TransformerMixin):
def __init__(self, attribute_names):
self.attribute_names = attribute_names
def fit(self, X, y=None):
return self
def transform(self, X):
return X[self.attribute_names].values

4단계는 여기까지입니다. 갈수록 어려워지는 것 같습니다. 다시 앞 단계 내용을 복습하면서 머리속에 정리해 넣어야겠습니다. ㅜㅜ
  

머신러닝 프로젝트 실행-1

(1~2단계: 1. 문제정의하고 전체 그림 바라보기/ 2. 데이터 얻기바로가기 


머신러닝 프로젝트 실행-2

(3단계: 인사이트를 찾기 위해 데이터 탐색하기바로가기 


참고)'Hands-On Machine Learning with Scikit-Learn and TensorFlowchapter 2' 

주피터 노트북에서 볼 수 있는 전체 코드 얻기


반응형
반응형

머신러닝(Machine Learning) 기본 개념(Basci Concept)

머신러닝은 주어진 데이터를 훈련시켜(training), 훈련된 지식을 기반으로 새로운 입력(test input)에 대해 적절한 답(test output)을 찾고자 하는 일련의 과정이라고 말할 수 있습니다. 

이때 훈련시키는 데이터가 질문(training input)과 정답(training output)이 모두 주어진 경우가 있고, 질문만 주어진 경우가 있습니다. 전자의 경우를 라벨링(Labeling)이 되어 있다고 말합니다.


1. 지도학습(Supervised Learning)

훈련 데이터에 라벨링이 되어 있는 경우. 

즉, 각 질문(input)에 대해 무엇이 정답(output)인지 훈련데이터가 알고 있는 경우입니다. 

예를 들면 (2, 4) -> (8), (4, 3) -> (12), 이런 식으로 훈련데이터가 주어져 있다는 것입니다.

ex) regression - (x,y)글의 데이터를 가지고 모함수 y=f(x)의 관계를 예측하는 방법

Classification - 각 그룹별 특징을 학습하여 새로운 데이터가 어느 그룹에 속해야 하는지 판단하는 방법


2. 비지도학습(Unsupervised Learning)

데이터만 잔뜩 주어집니다. 

즉 문제는 있는데 답은 없습니다. 

우리가 할 수 있는 건, 문제 유형 정도를 구분할 수 있겠습니다. 

이를 clustering이라고 합니다.  

ex) clustering - 어떠한 데이터끼리 군집으로 묶을 수 있는지 판단하는 방법

Dimension reduction - 독립적인 특징(축)들을 추출해 이를 중심으로 데이터를 압축하는 저차원으로 압축하는 방법


★ 요즘 비지도학습에 PCA(Principle Component Analysis, 주성분 분석) 알고리즘을 적용하고 딥러닝(Deep Learning)+오토엔코더(Autoencoder)로 확대되면서 인공지능 분야를 가장 핫한 분야가 되게 하였습니다.  이 부분은 나중에 정리해 보도록 하겠습니다.


3. 강화학습(Reinforcement Learning)

미리 정답이 주어져 있진 않고, 시행마다 잘한 정도를 보상(reward)하여 줍니다(이는 동물들이 학습하는 방법과 유사).

ex) 엘레베이터 스케쥴링, 컴퓨터 체스, 복잡한 로봇의 제어 등등


4. 그 외 : 일부만 라벨링이 되어 있는 경우도 있고, 정보가 점진적으로(incremental) 주어지는 경우도 있고, 데이터가 너무 많은 경우, 적은 경우 등 다양한 기계학습 문제가 존재합니다.



아래 그림은 scikit-learn(파이썬에서 많이 사용하고 있는 머신러닝 라이브러리) 관련 사이트에서 머신러닝 알고리즘을 한 눈에 볼 수 있도록 맵으로 제시하고 있습니다. 


머신 러닝에 대한 전체 윤곽을 그려볼 수 있어서 앞으로 머신러닝을 배워나가는 길잡이로 알고 있으면 좋습니다. 


원본 맵 보기(http://scikit-learn.org/stable/tutorial/machine_learning_map/)


반응형
반응형

4차 산업혁명 시대의 데이터 사이언티스트(Data Scientist)를 위한 파이썬 라이브러리(Python Library)

요즘 파이썬을 배워서 진출할 수 있는 직업 중에 데이터 사이언티스트가 핫한 것 같다. 4차 산업혁명과 함께 많이들 선호하고 있는 상태가 되었다.

하지만, 언론, 소셜 등에서 너무 많은 관심을 보이는 것이 거품이 될까 우려가 좀 된다. 2000년 초에 인터넷 기업 붐이 엄청나게 일어나고, 갑자기 거품이 꺼졌을 때 처럼 될 것 같아 보이기 때문이다. 


요즘 가장 열광하는 단어는 단연 AI일 것이라고 생각한다. 

그런데, 머신러닝(machine learning), 그 중에서 딥 러닝(deep learning)에 집중하는 것은 인터넷 자체가 혁신을 일으킬 것처럼 말했던 상황을 답습하는 것이 아닐까 하는 생각이 든다.


가장 중요한 것은 고객에게 제공하는 서비스, 제품일 것이다. 그래서 고객의 요구사항(애로사항)을 파악하는 것이 무엇보다 중요할 것이다. 

이런 관점을 갖고, 데이터와 AI의 결합을 바탕으로 고객들이 원하는 서비스(제품)을 만드는 기업 또는 사람이 되어야 한다고 믿는다.


'소프트웨어(데이터)가 모든 세계를 지배하는 세상'이라는 말은 디지털화된 데이터와 그것을 다루는 기술인 AI(그 중에서 머신 러닝)가 보편화된 세상을 말한다고 본다. 인터넷처럼 우리 생활에 스며들 것이기 때문에,  AI를 다루는 것과 데이터를 다루는 것은 기본이 될 것이다. 

앞으로 이것을 통해 어떤 가치를 고객에게 제공하느냐가 중요한 생존의 문제가 될 것이라는 것이다. 

사람들이 필요로 하는 가치(서비스, 제품)을 제공하는 수준까지 가기 위한 여정을 막 시작했다고 생각한다.

 

그럼, 가장 기본이 되는 라이브러리부터 알아보도록 하자.


데이터 사이언티스트들이 파이썬에서 사용하는 라이브러리들은 Numpy, Scipy, Pandas, Scikit-Learn 등이 있다. 


요즘에는 구글의 딥 러닝 라이브러리인 tensorflow의 인기가 높다.

tensorflow에 대해서는 따로 알아보도록 할 것이다.


1. Numpy, Scipy

Numpy와 Scipy는 숫자 및 과학 계산을 수행하기 위한 라이브러리라고 할 수 있다

Numpy는 기본 계산 기능을 가진 다차원 배열과 유용한 선형대수학 함수를 지원한다.

Scipy는 숫자 알고리즘 집합과 신호 처리, 최적화, 통계 등을 포함한 도메인에 특화된 기능을 지원한다.


(참고로, Matplotlib는 데이터 시각화를 위한 많은 툴을 가지고 있다)


2. Pandas

Pandas는 고성능의 데이터 구조와 데이터 분석 툴을 제공한다. 

Pandas의 주요 특징은 통합된 인덱싱과 함께 데이터 조작이 가능한 빠르고 효율적인 DataFrame 객체이다. 

DataFrame 구조는 매우 유연한 방법들로 작업이 가능한 스프레드시트처럼 볼 수 있다.

 재구조화하고, 행과 열을 추가하거나 제거하는 것을 통해 원하는 방식으로 어떤 데이타셋으로든 쉽게 변경할 수 있다. 

또한 데이터셋 간에 계산을 하고, 병합하고, 합류하는 고성능의 기능을 제공한다. 


또한, Pandas는 다른 형태의 포멧(CSV, EXCEL, SQL 데이터베이스, HDF5)으로부터 데이터를 가져오거나 내보낼 수 있는 툴을 가지고 있다. 

많은 경우, 이들 포멧들에 있는 데이터는 완벽하거나 전체적으로 구조화되어 있지 않을 것이다. 그런 경우, Pandas는 빠진 데이터를 핸들링하고 지능적으로 데이터를 정렬할 수 있도록 해준다. 

게다가, Pandas는 편리한 Matplotlib 인터페이스를 제공한다.


3. Scikit-learn

Scikit-learn은 Numpy, Scipy와 Matplotlib로 만들어진 머신 러닝 라이브러리이다.

Scikit-learn은 계층화, 회귀, 클러스터링, 차원 감소, 모델 선택과 전처리 같은 데이터 분석에 필요한 단순하고 효과적인 툴을 제공한다.



PS) 라이브러리별로 첨부한 정리 시트를 제공하는 원본 출처 및 원본 시트를 받고자 하시면 아래 링크를 보시기 바랍니다.


https://www.continuum.io/blog/developer-blog/learning-python-data-science-cheat-sheets



다음 편에는 Jupyter Notebook 환경에 대해 알아보도록 할 예정이다.


그럼 이만...



반응형

+ Recent posts