본문 바로가기
Data Science/케라스 공부

[핸즈온 머신러닝2][리뷰] Chapter 2 머신러닝 프로젝트 처음부터 끝까지 (데이터 전처리 부분)

by titaniumm 2021. 1. 9.

CHAPTER 씩 공부를 하면서 복습 겸 나중에 참고 할 수 있도록 정리를 해보려고 합니다.

1. OS, 데이터 다운로드 , 압축, 풀기

 데이터를 분석할때 다운로드를 해서 파일에 저장하고 그냥 read_csv 등으로 읽어오는 경우가 많았다. 매번 다운로드 폴더를 지정하고 압축을 풀어줘야하는 번거로움이 발생한다. 또한, 다른 컴퓨터로 옮겨서 작업할때 경로 등의 문제로 셋팅에 신경을 써줘야 하지만 이렇게 파이썬에서 제공하는 함수들을 이용하면 앞으로도 편리 할 것 같다. 

 

import os
import tarfile # 압축 파일과 관련
import urllib # url로 접근 시 활용

DOWNLOAD_ROOT = "https://raw.githubusercontent.com/rickiepark/handson-ml2/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") # zip파일 경로 설정
    urllib.request.urlretrieve(housing_url, tgz_path) # 인터넷에서 다운 받고 싶을때 쓰는 urlretrieve 로 zip파일 접근
    housing_tgz = tarfile.open(tgz_path)#경로 열기 
    housing_tgz.extractall(path=housing_path) #압축 파일 풀기 extractall
    housing_tgz.close()

CS 지식이 부족해서 그런지.. 두가지 궁금증이 생겼다.

 

1. 왜 urllib.request.urlretrieve 를 해줘야 하는지?

2. open close 가 정확히 무엇을 열고 닫는것인지..??

 

2. 데이터 살펴보기

기본적으로 활용할 수 있는 함수들이다. NULL의 개수를 파악하거나 데이터의 대략적인 분포(단위, 값 스케일)등 을 파악해 볼 수 있다.

# 1. 기본 특성 파악

housing.head() #상위 5줄 추출
housing.info() #NULL 이나 타입 파악 할 때 유용
housing.describe() # 컬럼별 수치들의 나타내주기 

# 2. 컬럼의 어떤 값들이 있는지 확인 해보기
%matplotlib inline
from matplotlib import pyplot as plt
housing["ocean_proximity"].value_counts() # 특정 컬럼의 데이터 표현
housing["median_income"].hist() #특정 컬럼 히스토그램
housing.hist(bins= 50,figsize=(20,15)) # bins 는 구간을 figsize는 크기를 설정한다
plt.show() #선택사항

 

 

3.  테스트셋 분리하기

Dataset을 test와 train을 분리하는 방법은 여러가지가 있다. 분리해야 하는 이유는 생략하고, 책에서 핵심적인 부분은 

단순히 랜덤하게 8:2로 나누는 것이 아닌 특징을 살려서 데이터셋을 분리하는 것이다.

 

주택 가격과 관련이 있는 housing 데이터셋은 medain_income 을 기준으로 분리한다. 특정 소득이 train 이나 test에 몰려있는 것을 방지하기 위함이다. 즉 분리한 데이터가 전체를 대변할 수 있도록 만드는 것이 핵심적이다.

 

그 전에 여러 값을 (범주형 데이터) 해당 변수를 카테고리화 하는 것이 중요하다.

아래 처럼 복잡한 경우는 Split 객체를 활용할 수도 있겠지만, 보편적으로는 train_test_split의 stratify설정을 통해서 범주형 특성을 고려해서 나눌 수 있다. 

-------------------------------train_test_split 활용-------------------------------------------

from sklearn.model_selection import train_test_split
train_set , test_set = train_test_split(housing,test_size = 0.2,stratify=housing["income_cat"])




-------------------------------split 객체를 활용한 방법-------------------------------------------

#다양한 수치였던 데이터들을 5개의 레이블로 분류한것을 알 수 있다. 
housing["income_cat"] = pd.cut(housing["median_income"], bins = [0.,1.5,3.0,4.5,6.,np.inf],labels = [1,2,3,4,5])
housing["income_cat"].value_counts()

#계층형 SPLIT 방식
#n_splits 는 한번만 실행
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]

 

4.  데이터 시각화 하기

scatter 산점도를 그리는 방식과 각각 변수의 쓰임이다.

추가로 지도와 함께 결합하는 방법도 인프런 강좌에서는 설명하고 있다. 

#1. 산점도
housing.plot(kind = 'scatter',x='longitude',y='latitude',alpha=0.4,
            s = housing["population"]/100,label='population',figsize=(10,7),
            c='median_house_value',cmap=plt.get_cmap('jet'),colorbar=True,sharex=False)

#sharex 는 버그로 인해서 넣어주어야 x축 레이블이 생성된다
#jet맵 형식
#alpha로 투명도 조절하기

#2. 상관관계
corr_matrix = housing.corr()
#특정 컬럼에 따라 상관관계 높은 순으로 나열하는 방법
corr_matrix["median_house_value"].sort_values(ascending = False)

상관관계와 각 변수들의 관계를 산점도로 구할 수 있는데, 이는 변수들의 관계를 파악하는데 중요한 지표를 나타낸다. 또한, 변수들을 조합하면 기존의 상관계수보다 높일 수 있다는 것을 기억하자! ( EX. 방의개수/인원 수 가 각각 보다 집 가격과 상관계수가 높다.)  

 

5. NULL 처리 방법 및 데이터 다루기

isnull, fillna, dropna 를 활용하여 NULL의 비율 그리고 채우거나 삭제가 가능하다.

sample_incomplete_rows = housing[housing.isnull().any(axis=1)].head() # NULL이 들어있는 변수들 파악, NULL의 비율 구할때 활용
#dropna fillna 를 활요하여 null 값 추가 혹은 삭제 가능

 

위의 방법으로 처리하는 것은 한계가 많다. 전체를 일괄적으로 추가 삭제해야하는데 컬럼별로 특성이 다르게 되면 채워야 하는 방식도 다르고 동일한 값으로 채우지 않기 때문이다.

 

숫자형의 경우는 싸이킷런의 IMPUTER를 활용한다.

from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy="median") # mean, most_frequent, constant등의 방법도 있음
#또한, 문자열이 있다면 제거하고 다시 생성해 주어야 한다.
#housing.select_dtypes(include= [np.number])등의 방법도 존재한다.
imputer.fit(housing_num)
X =imputer.transform(housing_num)

문자형의 경우는 A B C 분류된경우를 1,2,3 으로 변환해 주어야 한다. ("ocean_proximity") 의 경우이다. 

이후에는 transform과 fit_transform 함수를 직접 만들어서 변환/커스터마이징 하는 부분을 다룬다.

이 부분은 나중에 실력이 더 쌓이면 살펴볼 예정이다. 

#문자 분류된것을 숫자로
from sklearn.preprocessing import OrdinalEncoder
ordinal_encoder = OrdinalEncoder()
housing_cat_encoded = ordinal_encoder.fit_transform(housing_cat)


# 웟핫인코딩
from sklearn.preprocessing import OneHotEncoder
housing_cat_1hot = cat_encoder.fit_transform(housing_cat)
housing_cat_1hot

 

pipeline 이라고 불리는 클래스를 활용하는 것도 전처리 과정을 나열하고 정리하는데 굉장히 중요할것 같다. 

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_pipeline = Pipeline([
        ('imputer', SimpleImputer(strategy="median")),
        ('attribs_adder', CombinedAttributesAdder()),
        ('std_scaler', StandardScaler()),
    ])

housing_num_tr = num_pipeline.fit_transform(housing_num)

 

댓글