2.3 데이터 가져오기

2.2 큰 그림 보기 | 목차 | 2.4 데이터 이해를 위한 탐색과 시각화

 

이제 직접 키보드를 두드릴 차례입니다. 노트북을 꺼내서 주피터 노트북에 있는 다음 코드 예제를 따라 해보세요. 전체 주피터 노트북은 https://github.com/rickiepark/handson-ml 6에 있습니다.

 

2.3.1 작업환경 만들기

먼저 파이썬이 설치되어 있어야 합니다. 여러분 컴퓨터에는 이미 설치되어 있을 것입니다. 그렇지 않다면 http://www.python.org/ 에서 내려받을 수 있습니다.7

그다음엔 머신러닝 코드와 데이터셋을 저장할 작업 디렉터리를 만듭니다. 터미널을 열고 다음 명령을 실행합니다($ 프롬프트 다음이 명령입니다).

$ export ML_PATH="$HOME/ml" # 원하는 경로로 바꿔도 됩니다.
$ mkdir -p $ML_PATH

필요한 파이썬 패키지가 많이 있습니다. 주피터, 넘파이, 판다스, 맷플롯립, 사이킷런입니다. 이미 이 패키지들을 설치했다면 2.3.2절 ‘데이터 다운로드’로 건너뛰어도 됩니다. 아직 이 패키지들이 없다면 (의존성이 있는 다른 패키지도 포함해서) 설치할 수 있는 방법은 여러 가지입니다. 시스템의 패키징 도구를 사용할 수 있고(예를 들면 우분투의 apt-get, macOS의 맥포츠MacPorts나 홈브류Homebrew), 아나콘다 같은 과학 파이썬 배포판을 설치하고 딸려오는 패키징 도구8를 사용하거나, 그냥 파이썬 바이너리 인스톨러에 (파이썬 2.7.9부터) 기본으로 포함된 자체 패키징 도구인 pip를 사용할 수도 있습니다.9 시스템에 pip가 설치되어 있는지 다음 명령으로 확인합니다.

$ pip3 --version
pip 9.0.1 from [...]/lib/python3.5/site-packages (python 3.5)

최신 버전의 pip가 설치되어 있는지 확인해야 합니다. 바이너리 패키지(휠wheel이라고도 합니다) 설치를 지원하기 위해 최소한 1.4 버전보다 높아야 합니다. pip 패키지를 업그레이드하려면 다음 명령을 실행합니다.10

$ pip3 install --upgrade pip
Collecting pip
[...]
Successfully installed pip-9.0.1

독립적인 환경 만들기

독립된 개발 환경(다른 프로젝트의 라이브러리 버전과 충돌하는 것을 피하기 위해 권장하는 방법입니다)을 선호한다면 다음 pip 명령으로 virtualenv를 설치하세요.

$ pip3 install --user --upgrade virtualenv
Collecting virtualenv
[...]
Successfully installed virtualenv

그런 다음 독립적인 파이썬 환경을 다음과 같이 만들 수 있습니다.

$ cd $ML_PATH
$ virtualenv env
Using base prefix '[...]'
New python executable in [...]/ml/env/bin/python3.5
Also creating executable in [...]/ml/env/bin/python
Installing setuptools, pip, wheel...done.

이 환경을 활성화하려면 터미널을 열고 다음 명령을 입력합니다.

$ cd $ML_PATH
$ source env/bin/activate

환경이 활성화되면 pip 명령으로 설치하는 어떤 패키지든 독립된 이 환경에 설치되고 파이썬은 이 패키지만 사용하게 됩니다(시스템에 설치된 패키지를 사용하고 싶다면 virtualenv 환경을 만들 때 –system-site-packages 옵션을 사용해야 합니다). 더 자세한 정보는 virtualenv 문서를 참고하세요.11

이제 다음 pip 명령으로 필요한 패키지와 의존성으로 연결된 다른 패키지를 모두 설치합니다.

$ pip3 install --upgrade jupyter matplotlib numpy pandas scipy scikit-learn
Collecting jupyter
  Downloading jupyter-1.0.0-py2.py3-none-any.whl
Collecting matplotlib
  [...]

설치된 것을 확인하려면 다음과 같이 패키지를 모두 임포트해보세요.

$ python3 -c "import jupyter, matplotlib, numpy, pandas, scipy, sklearn"

어떤 에러나 메시지도 출력되지 않아야 합니다. 이제 다음 명령으로 주피터를 실행합니다.

$ jupyter notebook
[I 15:24 NotebookApp] Serving notebooks from local directory: [...]/ml
[I 15:24 NotebookApp] 0 active kernels
[I 15:24 NotebookApp] The Jupyter Notebook is running at: http://localhost:8888/
[I 15:24 NotebookApp] Use Control-C to stop this server and shut down all
kernels (twice to skip confirmation).

주피터 서버가 터미널에서 실행되었고 포트 8888번에 대기 중입니다. 웹 브라우저를 사용해 http://localhost:8888/ 주소로 서버에 접근할 수 있습니다(보통 서버가 시작될 때 자동으로 브라우저를 띄워 연결해줍니다). 현재 작업공간 디렉터리가 보일 것입니다(virtualenv 설정을 그대로 따라했다면 env 디렉터리만 있습니다).

New 버튼을 클릭하고 적절한 파이썬 버전을 선택해 새로운 주피터 노트북12을 만듭니다(그림2-3).

이 과정에서 세 가지 작업이 일어납니다. 첫째, 작업공간 안에 Untitled.ipynb라는 이름의 새로운 노트북 파일을 만듭니다. 둘째, 이 노트북을 실행하기 위한 주피터 파이썬 커널을 구동시킵니다. 셋째, 새로운 브라우저 탭에서 이 노트북을 엽니다. 시작하기 전에 이 노트북의 Untitled를 클릭해서 이름을 ‘Housing’으로 바꿉니다(이렇게 하면 자동으로 파일 이름이 Housing.ipynb로 변경됩니다).

그림 2-3 주피터 작업공간

노트북은 여러 셀cell을 포함합니다. 각 셀에는 실행 코드나 포맷된 텍스트를 넣을 수 있습니다. 처음엔 노트북에 ‘In [1]:’이라고 이름이 붙은 빈 코드 셀 하나만 있습니다. 셀에p rint(“Hello world!”)라고 입력하고 play 버튼이나 Shift-Enter 키를 눌러보세요. 이 명령은 현재 셀의 내용을 파이썬 커널에 보내 실행하고 그 결과를 돌려받습니다. 결과가 셀의 아래에 표시되고 노트북의 마지막 셀에 다다랐으므로 새로운 셀이 자동으로 생성됩니다. 주피터의 Help 메뉴에서 User Interface Tour를 사용해 기본 사용법을 익혀보세요.

그림 2-4 Hello world 주피터 노트북

 

2.3.2 데이터 다운로드

일반적으로 여러분이 다룰 데이터는 관계형 데이터베이스(또는 다른 데이터 저장소)에 들어있고 여러 테이블, 문서, 파일로 나뉘어 있을 것입니다. 이런 데이터에 접근하려면 먼저 보안 자격과 접근 권한이 있어야 하고13 그 데이터의 구조를 잘 알고 있어야 합니다. 하지만 이 프로젝트는 간단합니다. 모든 데이터가 들어 있는 CSVcomma-separated value 파일인 housing.csv를 압축한 housing.tgz 파일을 내려받기만 하면 됩니다

웹 브라우저를 사용해 이 파일을 내려받고 tar xzf housing.tgz 명령을 실행해서 압축을 풀어 CSV 파일을 얻을 수 있지만, 간단한 함수를 만들어 사용하면 더 편합니다. 특히 데이터가 정기적으로 변경되면 최근 데이터가 필요할 때마다 스크립트를 실행하면 되니 유용합니다(또는 스케줄링하여 주기적으로 자동 실행할 수도 있습니다). 데이터를 내려받는 일을 자동화하면 여러 기기에 데이터셋을 설치해야 할 때도 편리합니다.

다음 코드가 데이터를 추출하는 함수입니다.14

import os
import tarfile
from six.moves import urllib

DOWNLOAD_ROOT = "https://raw.githubusercontent.com/ageron/handson-ml/master/"
HOUSING_PATH = os.path.join("datasets", "housing")
HOUSING_URL = DOWNLOAD_ROOT + "datasets/housing/housing.tgz"

def fetch_housing_data(housing_url=HOUSING_URL, housing_path=HOUSING_PATH):
    if not os.path.isdir(housing_path):
        os.makedirs(housing_path)
    tgz_path = os.path.join(housing_path, "housing.tgz")
    urllib.request.urlretrieve(housing_url, tgz_path)
    housing_tgz = tarfile.open(tgz_path)
    housing_tgz.extractall(path=housing_path)
    housing_tgz.close()

fetch_housing_data ( )를 호출하면 작업공간에 datasets/housing 디렉터리를 만들고 housing.tgz 파일을 내려받고 같은 디렉터리에 압축을 풀어 housing.csv 파일을 만듭니다.

이제 판다스를 사용하여 데이터를 읽어 들이겠습니다. 데이터를 읽어 들이는 간단한 함수도 하나 만듭니다.

import pandas as pd

def load_housing_data(housing_path=HOUSING_PATH):
    csv_path = os.path.join(housing_path, "housing.csv")
    return pd.read_csv(csv_path)

이 함수는 모든 데이터를 담은 판다스의 데이터프레임 객체를 반환합니다.

 

2.3.3 데이터 구조 훑어보기

DataFrame의 head() 메서드를 사용해 처음 다섯 행을 확인해보겠습니다(그림 2-5).

그림 2-5 데이터셋의 처음 다섯 행

각 행은 하나의 구역을 나타냅니다. 특성은 longitude, latitude, housing_median_age, total_rooms, total_bedrooms, population, households, median_income, median_house_value, ocean_proximity 등 10개입니다(그림에는 6개만 보입니다).

info() 메서드는 데이터에 대한 간략한 설명과 특히 전체 행 수, 각 특성의 데이터 타입과 널null이 아닌 값의 개수를 확인하는 데 유용합니다(그림 2-6).

그림 2-6 housing.info() 결과

데이터셋에 20,640개의 샘플이 들어 있습니다. 머신러닝 프로젝트치고는 상당히 작은 편이지만, 처음 시작하기에는 적당한 크기입니다. total_bedrooms 특성은 20,433개만 널 값이 아닙니다. 207개의 구역은 이 특성을 가지고 있지 않다는 것을 뜻합니다. 나중에 이 문제를 적절히 처리하겠습니다.

ocean_proximity 필드만 빼고 모든 특성이 숫자형입니다. ocean_proximity 필드의 데이터 타입이 object이므로 어떤 파이썬 객체도 될 수 있지만, 데이터를 CSV 파일에서 읽어 들였기 때문에 텍스트 특성일 것입니다. 처음 다섯 행을 출력했을 때 ocean_proximity 열의 값이 반복되는 것으로 보아서15 이 특성은 아마도 범주형categorical일 것입니다. 어떤 카테고리가 있고 각 카테고리마다 얼마나 많은 구역이 있는지 value_counts() 메서드로 확인합니다.

>>> housing["ocean_proximity"].value_counts()
<1H OCEAN 9136
INLAND 6551
NEAR OCEAN 2658
NEAR BAY 2290
ISLAND 5
Name: ocean_proximity, dtype: int64

다른 필드도 살펴보겠습니다. describe() 메서드는 숫자형 특성의 요약 정보를 보여줍니다(그림 2-7).

그림 2-7 숫자형 특성의 요약 정보

count, mean, min, max 행이 의미하는 바는 쉽게 알 수 있습니다. 널 값이 제외된 것을 볼 수 있습니다(예를 들어 total_bedrooms의 count는 20,640이 아니고 20,433입니다). std 행은 값이 퍼져 있는 정도를 측정하는 표준편차를 나타냅니다.16 25%, 50%, 75% 행은 백분위수percentile를 나타냅니다. 백분위수는 전체 관측값에서 주어진 백분율이 속하는 하위 부분의 값을 나타냅니다. 예를 들어 25%의 구역은 housing_median_age가 18보다 작고, 50%는 29보다 작고, 75%는 37보다 작습니다. 이를 25번째 백분위수(또는 제1사분위수), 중간값, 75번째 백분위수(또는 제3사분위수)라고도 합니다.

데이터의 형태를 빠르게 검토하는 다른 방법은 각 숫자형 특성을 히스토그램으로 그려보는 것 입니다. 히스토그램은 주어진 값의 범위(수평축)에 속한 샘플 수(수직축)를 나타냅니다. 특성마다 따로 히스토그램을 그릴 수도 있고 전체 데이터셋에 대해 hist() 메서드를 호출하면 모든 숫자형 특성에 대한 히스토그램을 출력합니다(그림 2-8). 예를 들어 median_house_value가 약 $100,000인 구역은 800개가 조금 넘는 것을 볼 수 있습니다.

%matplotlib inline # 주피터 노트북의 매직 명령
import matplotlib.pyplot as plt
housing.hist(bins=50, figsize=(20,15))
plt.show()
NOTE_ hist() 메서드는 맷플롯립을 사용하고 결국 화면에 그래프를 그리기 위해 사용자 컴퓨터의 그래픽 백엔드를 필요로 합니다. 그래서 그래프를 그리기 전에 맷플롯립이 사용할 백엔드를 지정해줘야 합니다. 주피터의 매직 명령 %matplotlib inline을 사용하면 편리합니다. 이 명령은 맷플롯립이 주피터 자체의 백엔드를 사용하도록 설정합니다. 그러면 그래프는 노트북 안에 그려지게 됩니다.17 주피터 노트북에서 그래프를 그릴 때 show() 메서드를 호출하는 것은 선택사항입니다. 주피터는 셀이 실행될 때 자동으로 그래프를 그려 줍니다.

그림 2-8 모든 숫자형 특성에 대한 히스토그램

이 히스토그램에서 몇 가지 사항을 확인할 수 있습니다.

  1. 먼저 중간 소득median income 특성이 US 달러로 표현되어 있지 않은 것 같습니다.18 데이터를 취합한 팀에 확인해보니 스케일을 조정하고, 상한이 15(실제로는 15.0001), 하한이 0.5(실제로는 0.4999)가 되도록 만들었다고 합니다. 머신러닝에서는 전처리된 데이터를 다루는 경우가 흔하고 이것이 문제가 되지는 않지만 데이터가 어떻게 계산된 것인지 반드시 이해하고 있어야 합니다.
  2. 중간 주택 연도housing median age와 중간 주택 가격median house value 역시 최댓값과 최솟값을 한정했습니다.19 중간 주택 가격의 경우는 타깃 속성(레이블)으로 사용되기 때문에 심각한 문제가 될 수 있습니다. 가격이 한곗값을 넘어가지 않도록 머신러닝 알고리즘이 학습될지도 모릅니다. 이것이 문제가 될지 안 될지는 클라이언트 팀(이 시스템의 출력을 사용할 팀)과 함께 검토하는 것이 좋습니다. 만약 그 팀에서 $500,000를 넘어가더라도 정확한 예측값이 필요하다고 한다면 우리가 선택할 수 있는 방법은 두 가지입니다.
    • 한곗값 밖의 구역에 대한 정확한 레이블을 구합니다.
    • 훈련 세트에서 이런 구역을 제거합니다($500,000가 넘는 값에 대한 예측은 평가 결과가 매우 나쁠 것이므로 테스트 세트에서도 제거합니다).
  3. 특성들의 스케일이 서로 많이 다릅니다. 특성 스케일링에 대해서는 이 장의 뒷부분에서 살펴보겠습니다.
  4. 마지막으로 많은 히스토그램의 꼬리가 두껍습니다. 가운데에서 왼쪽보다 오른쪽으로 더 멀리 뻗어 있습니다. 이런 형태는 일부 머신러닝 알고리즘에서 패턴을 찾기 어렵게 만듭니다. 나중에 이런 특성들을 좀 더 종 모양의 분포가 되도록 변형시키겠습니다.

이제 우리가 다룰 데이터를 많이 이해하게 되었습니다.

CAUTION_ 데이터를 더 깊게 들여다보기 전에 테스트 세트를 따로 떼어놓아야 합니다. 그리고 테스트 세트를 절대 들여다보면 안 됩니다.

 

2.3.4 테스트 세트 만들기

이 단계에서 데이터 일부를 자진해서 떼어놓으라는 것이 이상하게 들릴지 모르겠습니다. 지금까지 데이터를 잠시 살펴봤을 뿐이고 어떤 알고리즘을 사용할지 정하기 전에 전체 데이터를 자세히 파악해야 하지 않을까요? 사실 맞습니다. 하지만 우리 뇌는 매우 과대적합되기 쉬운 엄청난 패턴 감지 시스템입니다. 만약 테스트 세트를 들여다본다면 테스트 세트에서 겉으로 드러난 어떤 패턴에 속아 특정 머신러닝 모델을 선택하게 될지도 모릅니다. 이 테스트 세트로 일반화 오차를 추정하면 매우 낙관적인 추정이 되며 시스템을 론칭했을 때 기대한 성능이 나오지 않을 것입니다. 이를 데이터 스누핑data snooping 편향이라고 합니다.

테스트 세트를 생성하는 일은 이론적으로 매우 간단합니다. 그냥 무작위로 어떤 샘플을 선택해서 데이터셋의 20% 정도를 떼어놓으면 됩니다.

import numpy as np

def split_train_test(data, test_ratio):
    shuffled_indices = np.random.permutation(len(data))
    test_set_size = int(len(data) * test_ratio)
    test_indices = shuffled_indices[:test_set_size]
    train_indices = shuffled_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]

이 함수를 다음과 같이 사용할 수 있습니다.

>>> train_set, test_set = split_train_test(housing, 0.2)
>>> print(len(train_set), "train +", len(test_set), "test")
16512 train + 4128 test

좋네요. 이것도 괜찮지만 완벽하지는 않습니다. 프로그램을 다시 실행하면 다른 테스트 세트가 생성됩니다! 여러 번 계속하면 우리는(또는 우리 머신러닝 알고리즘이) 전체 데이터셋을 보는 셈이므로 이런 상황은 피해야 합니다.

한 가지 해결책은 처음 실행에서 테스트 세트를 저장하고 다음번 실행에서 이를 불러들이는 것입니다. 또 다른 방법은 항상 같은 난수 인덱스가 생성되도록 np.random.permutation()을 호출하기 전에 난수 발생기의 초깃값을 지정하는 것입니다(예를 들면 np.random.seed(42)20).

하지만 이 두 해법 모두 다음번에 업데이트된 데이터셋을 사용하려면 문제가 됩니다. 일반적인 해결책은 샘플의 식별자를 사용하여 테스트 세트로 보낼지 말지 정하는 것입니다(샘플이 고유하고 변경 불가능한 식별자를 가지고 있다고 가정합니다). 예를 들어 각 샘플마다 식별자의 해시값을 계산하여 해시의 마지막 바이트의 값이 51(256의 20% 정도)보다 작거나 같은 샘플만 테스트 세트로 보낼 수 있습니다. 이렇게 하면 여러 번 반복 실행되면서 데이터셋이 갱신되더라도 테스트 세트가 동일하게 유지됩니다. 새로운 테스트 세트는 새 샘플의 20%를 갖게 되지만 이전에 훈련 세트에 있던 샘플은 포함시키지 않을 것입니다. 다음은 이를 구현한 코드입니다.

from zlib import crc32

def test_set_check(identifier, test_ratio):
    return crc32(np.int64(identifier)) & 0xffffffff < test_ratio * 2**32

def split_train_test_by_id(data, test_ratio, id_column):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio))
    return data.loc[~in_test_set], data.loc[in_test_set]

안타깝게도 주택 데이터셋에는 식별자 컬럼이 없습니다. 대신 행의 인덱스를 ID로 사용하면 간단히 해결됩니다.

housing_with_id = housing.reset_index() # ‘index’ 열이 추가된 데이터프레임이 반환됩니다.
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "index")

행의 인덱스를 고유 식별자로 사용할 때 새 데이터는 데이터셋의 끝에 추가되어야 하고 어떤 행도 삭제되지 않아야 합니다. 이것이 불가능할 땐 고유 식별자를 만드는 데 안전한 특성을 사용해야 합니다. 예를 들어 구역의 위도와 경도는 몇백 년 후까지 안정적이라고 보장할 수 있으므로 두 값을 연결하여 다음과 같이 ID를 만들 수 있습니다.21

housing_with_id["id"] = housing["longitude"] * 1000 + housing["latitude"]
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "id")

사이킷런은 데이터셋을 여러 서브셋으로 나누는 다양한 방법을 제공합니다. 가장 간단한 함수는 train_test_split으로, 앞서 우리가 만든 split_train_test와 아주 비슷하지만 두 가지 특징이 더 있습니다. 첫째 앞서 설명한 난수 초깃값을 지정할 수 있는 random_state 매개변수가 있고, 둘째 행의 개수가 같은 여러 개의 데이터셋을 넘겨서 같은 인덱스를 기반으로 나눌 수 있습니다(이는 예를 들어 데이터프레임이 레이블에 따라 여러 개로 나뉘어 있을 때 매우 유용합니다).22

from sklearn.model_selection import train_test_split

train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)

지금까지는 순수한 무작위 샘플링 방식을 보았습니다. 데이터셋이 충분히 크다면(특히 특성 수에 비해) 일반적으로 괜찮지만, 그렇지 않다면 샘플링 편향이 생길 가능성이 큽니다. 설문조사 기관에서 1,000명에게 질문 몇 개를 하려 할 때 그냥 전화번호부에서 1,000명을 무작위로 뽑는 것이 아닙니다. 전체 인구를 대표할 수 있는 1,000명을 선택하기 위해 노력합니다. 미국 인구의 51.3%가 여성이고 48.7%가 남성이라면, 잘 구성된 설문조사는 샘플에서도 이 비율을 유지해야 합니다. 즉, 여성은 513명, 남성은 487명이어야 합니다. 이를 계층적 샘플링stratified sampling이라고 합니다. 전체 모수는 계층strata이라는 동질의 그룹으로 나뉘고, 테스트 세트가 전체 모수를 대표하도록 각 계층에서 올바른 수의 샘플을 추출합니다. 기본 무작위 샘플링을 사용하면 49%보다 적거나 54%보다 많은 여성이 테스트 세트에 들어갈 확률이 약 12%입니다.23 어느 방법을 사용하든 설문조사 결과를 크게 편향시키게 됩니다.

전문가가 중간 소득이 중간 주택 가격을 예측하는 데 매우 중요하다고 이야기해주었다고 가정합시다. 이 경우 테스트 세트가 전체 데이터셋에 있는 여러 소득 카테고리를 잘 대표해야 합니다. 중간 소득이 연속적인 숫자형 특성이므로 소득에 대한 카테고리 특성을 만들어야 합니다. 중간 소득의 히스토그램을 조금 더 자세히 살펴보겠습니다([그림 2-8] 참조). 중간 소득 대부분은 $20,000~$50,000 사이에 모여 있지만 일부는 $60,000를 넘기도 합니다. 계층별로 데이터셋에 충분한 샘플 수가 있어야 합니다. 그렇지 않으면 계층의 중요도를 추정하는 데 편향이 발생할 것입니다. 이 말은 너무 많은 계층으로 나누면 안 된다는 뜻이고 각 계층이 충분히 커야 합니다. 다음 코드는 중간 소득을 1.5로 나누고(소득의 카테고리 수를 제한하기 위해), ceil 함수를 사용하여 올림해서 소득 카테고리 특성을 만들고(이산적인 카테고리를 만들기 위해), 5보다 큰 카테고리는 5로 합칩니다.

housing["income_cat"] = np.ceil(housing["median_income"] / 1.5)
housing["income_cat"].where(housing["income_cat"] < 5, 5.0, inplace=True)

[그림 2-9]는 이 소득 카테고리의 히스토그램입니다.

그림 2-9 소득 카테고리의 히스토그램

이제 소득 카테고리를 기반으로 계층 샘플링을 할 준비가 되었습니다. 사이킷런의 StratifiedShuffleSplit를 사용할 수 있습니다.24

from sklearn.model_selection import StratifiedShuffleSplit

split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in split.split(housing, housing["income_cat"]):
    strat_train_set = housing.loc[train_index]
    strat_test_set = housing.loc[test_index]

의도대로 되었는지 살펴보겠습니다. 전체 주택 데이터셋에서 소득 카테고리의 비율을 먼저 살펴보겠습니다.

>>> housing["income_cat"].value_counts() / len(housing)
3.0 0.350581
2.0 0.318847
4.0 0.176308
5.0 0.114438
1.0 0.039826
Name: income_cat, dtype: float64

비슷한 코드로 테스트 세트에 있는 소득 카테고리의 비율을 측정합니다. [그림 2-10]은 전체 데이터셋과 계층 샘플링으로 만든 테스트 세트에서 소득 카테고리 비율을 비교한 것입니다. 그림에서 보듯이 계층 샘플링을 사용해 만든 테스트 세트가 전체 데이터셋에 있는 소득 카테고리의 비율과 거의 같습니다. 반면 일반 무작위 샘플링으로 만든 테스트 세트는 비율이 많이 달라졌습니다.

그림 2-10 계층 샘플링과 순수한 무작위 샘플링의 샘플링 편향 비교

이제 income_cat 특성을 삭제해서 데이터를 원래 상태로 되돌리겠습니다.25

for set_ in (strat_train_set, strat_test_set):
    set_.drop("income_cat", axis=1, inplace=True)

테스트 세트 생성에 대해 자세히 설명한 데는 그럴 만한 이유가 있습니다. 종종 등한시되기도 하지만 머신러닝 프로젝트에서 아주 중요한 부분이기 때문입니다. 게다가 이런 아이디어들은 나중에 교차 검증에 대해 이야기할 때 도움이 됩니다. 이제 데이터를 탐색하는 다음 단계로 넘어갑시다.

 


 

6 옮긴이_ 이 주소는 옮긴이의 저장소입니다. 저자의 저장소는 https://github.com/ageron/handson-ml 입니다.
7 파이썬 3의 최신 버전을 추천합니다. 파이썬 2.7+도 아직 괜찮지만 더 이상 업데이트되지 않습니다. 옮긴이_ 파이썬 2.7+는 2020년까지만 유지 관리됩니다.
8 옮긴이_ 아나콘다는 운영체제별로 사전에 컴파일된 많은 과학 패키지를 제공하며, 시스템의 기본 파이썬을 변경하지 않고 사용자 권한으로 다양한 버전의 파이썬을 설치할 수 있는 등 장점이 많아 대부분의 경우 권장하는 방법입니다. 아나콘다의 패키징 도구는 conda입니다. 윈도우에서 아나콘다를 설치하는 과정은 옮긴이의 블로그를 참고하세요(https://goo.gl/QmSUwF).
9 여기서는 리눅스나 macOS 시스템의 배시 셸(bash shell )에서 pip 명령을 사용한 설치 과정을 제시합니다. 윈도우에서는 아나콘다를 권장합니다.
10 이 명령을 실행하려면 시스템 어드민 권한이 필요할지 모릅니다. 이런 경우에는 앞에s udo 명령을 붙여서 시도해보세요.
11 옮긴이_ virtualenv 문서는 https://virtualenv.pypa.io/ 주소에서 확인할 수 있습니다.
12 주피터는 여러 버전의 파이썬을 지원하며 R이나 옥타브(Octave) 같은 다른 언어도 사용할 수 있습니다. 옮긴이_ 이 외에도 과학 계산용 언어 줄리아(Julia )와 대화형 C++(https://goo.gl/b8aJyR) 등 많은 언어를 지원합니다. 전체 주피터 커널 목록은 https://goo.gl/tjKunR 주소를 확인하세요.
13 또한 개인 정보가 담긴 필드가 안전하지 않은 저장소로 복사되지 않는 등의 법적 제약도 검토해야 합니다.
14 실제 프로젝트에서는 이 코드를 파이썬 파일에 저장하지만 여기서는 그냥 주피터 노트북에 작성합니다.
15 옮긴이_ [그림 2-5]에는 모든 열이 나타나 있지 않고 깃허브 주피터 노트북에서 전체 열을 확인할 수 있습니다. 처음 다섯 행의 ocean_proximity는 모두 ‘NEAR BAY’입니다.
16 옮긴이_ 표준편차는 일반적으로 \sigma(시그마)로 표기하고, 평균에서부터 떨어진 거리를 제곱하여 평균한 분산의 제곱근입니다. 어떤 특성이 정규분포(가우시안 분포)를 따르는 경우 약 68%의 값은 1\sigma 안에, 95%는 2\sigma 안에, 99.7%는 3\sigma 안에 있습니다.
17 옮긴이_ IPython kernel 4.4.0부터는 %matplotlib inline 매직 명령을 사용하지 않더라도 맷플롯립 1.5 이상에서는 자동으로 주피터 자체 백엔드로 설정됩니다.
18 옮긴이_ [그림 2-8]의 median_income 히스토그램을 보세요.
19 옮긴이_ 중간 주택 연도(housing_median_age)와 중간 주택 가격(median_housing_value) 히스토그램은 오른쪽에서 그래프가 심하게 높아지면서 히스토그램이 끝나는 것으로 보아 마지막 값으로 한정되었음을 짐작할 수 있습니다.
20 사람들은 난수 초깃값으로 42를 자주 사용합니다. 이 숫자는 ‘삶, 우주, 그리고 모든 것에 대한 궁극적인 질문의 해답’인 것 외에는 특별한 의미는 없습니다. 옮긴이_ 이 숫자는 더글러스 애덤스(Douglas Adams)의 소설 『은하수를 여행하는 히치하이커를 위한 안내서』에서 슈퍼컴퓨터인 깊은 생각(Deep Thought)이 이 질문에 대해 750만 년 동안 계산하여 내놓은 답입니다.
21 위치 정보는 사실 정밀도가 낮아 여러 구역의 ID가 동일해지므로 같은 테스트 세트 혹은 훈련 세트에 들어가게 됩니다. 이는 원치 않은 샘플링 편향을 만듭니다.
22 옮긴이_ train_test_split() 함수는 파이썬 리스트, 넘파이 배열, 판다스 데이터프레임과 판다스 시리즈(Series) 객체 등을 입력으로 받을 수 있습니다.
23 옮긴이_ 샘플 수가 n 이고 모수에서의 비율이 p 일 때 n \times p \ge 10 이고 n \times (1 - p) \ge 10 인 이항 분포는 평균이 np 고 표준편차가 \sqrt{np(1 - p)} 인 정규분포로 근사할 수 있습니다. 따라서 전체 인구 중 51.3%인 여성이 샘플에서 차지할 비율의 분포는 평균이 1000 \times 0.513 = 513 이고 표준편차가 1000 \times 0.513 \times (1 - 0.513) = 15.8 입니다. 평균이 513이고 표준편차가 15.8인 정규분포에서 490 이하와 540 이상인 부분의 면적은 약 11.65%입니다.
24 옮긴이_ StratifiedShuffleSplit는 StratifiedKFold의 계층 샘플링과 ShuffleSplit의 랜덤 샘플링을 합친 것으로 test_size와 train_size 매개변수의 합을 1 이하로 지정할 수도 있습니다.
25 옮긴이_ 판다스 데이터프레임의 drop 메서드는 행 또는 열을 삭제합니다. axis 매개변수의 기본값이 0일 때는 행을 삭제하고 1일 때는 열을 삭제합니다. 기본값이 False인 inplace 매개변수를 True로 설정하면 호출된 데이터프레임 자체를 수정하고 아무런 값도 반환하지 않습니다.
† 옮긴이_ crc32() 함수의 결과에 비트 연산을 하는 이유는 파이썬 2와 호환성을 유지하기 위해서 입니다.

 

2.2 큰 그림 보기 | 목차 | 2.4 데이터 이해를 위한 탐색과 시각화

 

이 글은 한빛미디어에서 출간한  “핸즈온 머신러닝“의 1장과 2장입니다. 이 책의 저작권은 한빛미디어(주)에 있으므로 무단 복제 및 무단 전제를 금합니다.

2.3 데이터 가져오기”에 대한 6개의 생각

    1. 박해선 글의 글쓴이

      안녕하세요. 깃허브 원본 다운로드 주소 형식이 변경되었네요. DOWNLOAD_ROOT = “https://github.com/rickiepark/handson-ml/raw/master/” 로 변경해 주세요.
      잘 못 말씀 드렸네요. 본문에 나온 주소에서 정상적으로 다운로드 됩니다. 파일이 다운이 안된 것인지 확인해 봐 주세요.

      좋아요

      응답
  1. pistolet

    를 참고하여 path 와 url을 설정하는 부분에 차이가 있다는 것을 확인하였습니다.
    HOUSING_PATH = os.path.join(“datasets”, “housing”)
    HOUSING_URL = DOWNLOAD_ROOT + “datasets/housing/housing.tgz”
    로 변경하여 실행하니 에러가 해결되었습니다.

    Liked by 1명

    응답

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

w

%s에 연결하는 중

This site uses Akismet to reduce spam. Learn how your comment data is processed.