페이지

2018년 7월 20일 금요일

2.3 데이터 가져오기

2.3.1 작업환경 만들기

2.3.2 데이터 다운로드

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

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

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

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

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

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

2.3.3 데이터 구조 흝어보기
DataFrame의 head() 메서드를 사용해 처음 다섯 행을 확인해보겠습니다.

각 행은 하나의 구역을 나타냅니다. 특성은 longitude, latitude, housing_median_age, total_rooms, tatal_bedrooms, population, households, median_incom, median_house_value, ocean_proximity등 10개입니다.

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

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

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

describe()메소드는 숫자형 특성의 요약 정보를 보여줍니다.

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

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

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

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

1. 먼저 중간 소득(median income)특성이 US달러로 표현되어 있지 않은 것 같습니다. 데이터를 취합한 팀에 확인해보니 스케일을 조정하고, 상한이 15(실제로는 15.0001), 하한이 0.5(실제로는 0.49999)가 되도록 만들었다고 합니다. 머신러닝에서는 전처리된 데이터를 다루는 경우가 흔하고 이것이 문제가 된지는 않지만 데이터가 어떻게 계산된 것인지 반드시 이해하고 있어야 합니다.

2. 중간 주택 연도(housing median age)와 중간 주택 가격(median house value)역시 최댓값과 최솟값을 한정햇습니다. 중간 주ㅐㄱ 가격의 경우는 타깃 속성(레이블)으로 사용되기 때문에심가한 문제가 될 수 있습니다. 가격이 한곗값을 넘어가지 않도록 머신러닝 알고리즘이 학습될지도 모릅니다. 이것이 문제가 될지 안될지는 클라이언트 팀(이 시스템의 출력을 사용할 팀)과 함께 검토하는 것이 좋습니다. 만약 그 팀에서 $500,000를 넘어가더라도 정확한 예측값이 필요하다고 한다면 우리가 선택할 수 있는 방법은 두가지입니다.

a. 한곗값 밖의 구역에 대한 정확한 레이블을 구합니다.
b. 훈련 세ㅡ에서 이런 구역을 제거합니다($500,000가 넘는 값에 대한 예측은 평가 결과가 매우 나쁠것이므로 테스트 세트에서도 제거합니다).

3. 특성들의 스케일이 서도 많이 다릅니다. 특성 스케일링에 대해서는 이 장의 뒷부분에서 살펴보겠습니다.
4. 마지막으로 많은 히스토그램의 꼬리가 두껍습니다. 가운데에서 왼쪽보다 오른쪽으로 더 멀리 뻗어 있습니다. 이런 형태는 일부 머신러닝 알고리즘에서 패턴을 찾기 어렵게 만듭니다. 나중에 이런 특성들을 좀 더 종 모양의 분포가 되도록 변형시키겠습니다.

이제 우리가 다룰 데이터를 많이 이해하게 되었습니다.
CAUTION_ 데이터를 더 갚게 들여다 보기 전에 테스트 세트를 따로 떠어놓아야 합니다. 그리고 테스트 세트를 절대 들여다보면 안 됩니다.

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

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

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

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

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

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

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



댓글 없음: