ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 머신러닝 02 - sklearn 알아 보기 (전처리)
    빅데이터/Machine-Learning 2022. 2. 7. 21:40

    패스트캠퍼스 '직장인을 위한 파이썬 데이터분석 올인원 패키치 Online' 참조

     

     

     

     

    01 전처리 기본

    • 전처리는 데이터를 분석에 적합하게 데이터를 가공/변형/처리/클리닝을 하는 작업이다
      'Garbage in, Garbage out!'
      데이터가 깔끔하지않으면(이상치가 많다거나) 성능이 현저하게 떨어진다. 
    • 분석가의 80%시간데이터 수집 및 전처리에 사용 한다고 전해진다. 

     

    - 전처리 과정은 다음과 같다

    1. 결측치 (Imputer) - 데이터의 빠진 부분을 처리
    2. 이상치 - 데이터에 이상치가 있을때 처리
    3. 정규화(Normalization)
    4. 표준화(Standardization)
    5. 샘플링(over/under smapling)
    6. 피처 공학(Feature Enginerring)
      - feature 생성/연산
      - 구간 생성, 스케일 변형

    ▶ 실습을 통해 하나씩 볼 예정

     

    - 정규화 (Normalization)

    • 0~1 사이의 분포로 조정
      데이터 = 데이터 최대값-최소값 / 데이터값-최소값을 하게 되면 0~1사이로 분포가 조정 된다
    • 대표적으로 정규화는 다른 스케일에 있는 데이터를 동일한 스케일에 넣거나 데이터 분포가 너무 넓게 퍼져있으면 성능을 제대로 나오지 않기 때문에 주로 하게 된다

     

    - 표준화(Standardization)

    • 평균을 0, 표준편차를 1로 맞춤
    • 데이터가 정규분포를 따른다는 가정하에 실시 (정규분포는 종모양의 분포). 평균은 0, 표준편차는 1이므로 변한 값이 0~1사이로 바뀌지 않게 된다. 하지만 평균은 0이므로 0의 근처로 많이 잡히게 된다.

     

     

    02 전처리 데이터 만들기

    • sklearn을 써서 train/validation/test set을 준비 해 보자
    * 테스트 셋을 나누기 위한 라이브러리
    
    import numpy as np
    import pandas as pd
    • 케글에서 제공해주는 데이터를 들고 오자!
      train = pd.read_csv('https://bit.ly/fc-ml-titanic')​
      train.head()

    타이타닉 사고에 대한 데이터다. Train-set에는 모든 데이터 내용이 들어 간다

     

    - Train/Validation 세트 나누기

    • 저번 강의 시간때 Train 80% / Validation 20% 정도로 데이터를 나눈다고 하였다. 이 비율 나누는것도 'sklearn'에서 제공해 준다
    • 먼저 학습데이터와 예측 데이터에 쓰일 목록들을 정하고 구분을 지어 주자. 
    # feature = 학습을 하기위한 컬럼
    feature = ['Pclass','Sex','Age','Fare']
    
    # label = 예측해야될 컬럼
    label = ['Survived']

    ▶ 'train' 데이터에서 리스트 형식으로 나눴기때문에 반드시 'train['']' 으로 호출 해야 한다

    • 이제 'sklearn'에서 제공하는 패키지를 써서 데이터셋을 나눠 보자
    from sklearn.model_selection import train_test_split # sklearn에서 제공하는 세트 분리 패키지
    
    # return 받는 데이터의 순서가 중요!!!
    x_train, x_valid, y_train, y_valid = train_test_split(train[feature], train[label], test_size=0.2, shuffle=True, random_state=30)
    # train_test_split('학습데이터','에측데이터','옵션1,2,3...'') 
    # 학습데이터는 train에, 예측데이터는 valid에 'sklearn'이 알아서 분류를 하여 넣어 준다
    
    - test_size : validation set에 할당하는 비율(20% -> 0.2)
    - shuffle : 셔플 옵션 (기본 True) - shuffle - 무작위, shuffle=False - 순차적
    - random_state : 랜덤 시드값 - 매번 테스트시 같은값을 받기위한 세팅 즉 30개를 매번 같은 값으로 받음)

    x = feature, y = label

    • 값이 동일하게 배분된것을 볼 수 있다 ((데이터량, 컬럼개수)) → feature 컬럼 4개, label 컬럼 1개
    • 총 891개의 데이터중 80%가 훈련으로, 20%가 검증으로 분리된것을 볼 수 있다

     

     

     

     

    03 숫자형(Numerical) 결측치 처리

    • 제일 먼저 .info()를 활용하면 개수를 통해 어디 부분이 결측치가 있는지 볼 수 있다
    train.info()

    • 이렇게 목록이 11개면 눈으로 체크가 가능하지만 80,90개로 늘어나면 특히 11번같은 데이터는 파악이 힘들 수 도 있다. 이럴때 꿀팁!
    # pandas의 isnull()을 써서 결측치 확인과 총 합을 이용해 한 눈에 확인
    train.isnull().sum()
    
    # 개별 결측치 확인
    # train['Age'].isnull().sum()

     

    • 결측치를 채워 보자
      # 결측치 처리
      # train['Age'].fillna(0).describe() - 결측치를 0으로 처리
      train['Age'].fillna(train['Age'].mean()).describe() # 결측치를 'Age' 컬럼의 평균으로 채움​

    714에서 결측치가 채워져 891이 되었다

    • 'sklearn' 패키지의 'imputer'를 써서 결측치 처리
    • imputer - 2개 이상의 column을 한번에 처리 할 때 사용
    # 'sklearn'의 패키지 'imputer'를 사용해서 결측치 처리
    # imputer - 2개 이상의 column을 한번에 처리 할 때 사용
    from sklearn.impute import SimpleImputer
    
    # imputer를 쓰기위해서 변수화를 진행하고 결측치를 'mean' 값으로 처리하겠다는 말
    imputer = SimpleImputer(strategy='mean')
    
    # .fit()을 통해 결측치 처리 학습 진행
    imputer.fit(train[['Age', 'Pclass']])
    
    # .transform() 을 해야 실제로 결측치에 대한 처리를 해줌
    result = imputer.transform(train[['Age','Pclass']])
    
    # 실제 결측치 처리 이후 다시 원 데이터 컬럼에 넣어 줘야 변함
    train[['Age', 'Pclass']] = result
    
    train[['Age', 'Pclass']].isnull().sum()
    train[['Age', 'Pclass']].describe()

    결측치 없이 꽉 채워 졌다

    ▶ 사실 .fit()/.transform() 을 합쳐서 할 수 있다 = .fin_transform()

     

     

     

     

    04 카테고리(Categorical) 결측치 처리

    • 숫자형 결측치 경우는 숫자를 넣어주거나 평균, 중앙값들로 채워 줄 수 있었다.
    • 문자형 처리를 배워 보자
    # 1개의 column 처리
    train['Embarked'].fillna('S').describe()
    
    # imputer를 써 2개 이상의 column 처리
    imputer = SimpleImputer(strategy='most_frequent') # 'most_frequent' - 가장 빈도수가 높은 것들로 채움
    
    result = imputer.fit_transform(train[['Embarked','Cabin']])
    
    train[['Embarked','Cabin']] = result
    
    train[['Embarked','Cabin']].isnull().sum()
    
    Embarked    0
    Cabin       0
    dtype: int64

     

     

     

    05 라벨 인코딩

    • 'Label Encoding'으로 문자(Categorical)를 수치(Numerical)로 변환
    • 머신러닝시에 기계는 절대로 문자를 인식 할 수 없음. 수치로 변환 시켜주는 작업이 필요함
    • Label Encoding 은 라이브러리의 하나로 각각의 다른 문자열에따라 알아서 숫자를 부여해주는 패키지
      (알파벳 순으로 정렬하고 그 정렬된 기준으로 숫자를 매김)

    성별 컬럼을 라벨 인코딩 해보자

    train['Sex'].value_counts()
    
    male      577
    female    314
    Name: Sex, dtype: int64
    • 함수화를 통해 진행하는 방법 1
    # 함수를 만들어 컬럼에 있는 데이터 형태를 보고 숫자를 리턴하도록 만들어야함
    def convert(data):
        if data == 'male':
            return 1
        elif data == 'female':
            return 0
            
            
    # 함수를 .apply() 를 통해 함수 적용이 가능 하도록 함
    train['Sex'].apply(convert)
    
    0      1
    1      0
    2      0
    3      0
    4      1
          ..
    886    1
    887    0
    888    0
    889    1
    890    1
    Name: Sex, Length: 891, dtype: int64
    • 이제 라벨인코더 패키지를 이용하여 진행 2
    # 라벨 인코더 임포트
    from sklearn.preprocessing import LabelEncoder
    le = LabelEncoder()
    
    train['Sex_num'] = le.fit_transform(train['Sex'])
    * Nan값이 있으면 라벨 인코더 정상 작동 안됨
    
    
    train['Sex_num'].value_counts
    
    <bound method IndexOpsMixin.value_counts of 0      1
    1      0
    2      0
    3      0
    4      1
          ..
    886    1
    887    0
    888    0
    889    1
    890    1
    Name: Sex_num, Length: 891, dtype: int32>
    #.classes_ -> 어떤 값들이 있었는지 확인 가능 
    le.classes_
    
    array(['female', 'male'], dtype=object)
    
    # .inverse_transform() -> 각 주소에 맞는 문자열을 리턴
    le.inverse_transform([0,1,1,0,0,1,1])
    
    array(['female', 'male', 'male', 'female', 'female', 'male', 'male'],
          dtype=object)

    * NaN 값이 있을 경우 오류가 뜰 수 있다. 이럴때는 NaN값을 채워주고 진행하면 된다.

     

     

     

    06 One Hot Encoding

    • 라벨 인코딩과 비슷하다. 라벨 인코딩의 경우 알파벳순으로 숫자를 매기기 때문에 랭크된 숫자 정보가 데이터에 잘못 반영이 될 수 있다
    • 쉽게 이야기 하면 목록화해서 개별로 그 목록값에 대한 이진값으로 만들어 주는 패키지
      (https://azanewta.tistory.com/46) 링크 참조!
    • 쉽게 아래 그림으로 보면 두개를 비교 할 수 있다.

     

    - 예를 보자

    train = pd.read_csv('https://bit.ly/fc-ml-titanic')
    
    train['Embarked'].value_counts()
    S    644
    C    168
    Q     77
    Name: Embarked, dtype: int64
    
    
    # 2개의 NaN 값 채우기
    train['Embarked'] = train['Embarked'].fillna('S')
    
    train['Embarked'].value_counts()
    S    646
    C    168
    Q     77
    Name: Embarked, dtype: int64
    
    #라벨 인코딩
    train['Embarked_num'] = LabelEncoder().fit_transform(train['Embarked'])
    
    train['Embarked_num'].value_counts()
    2    646
    0    168
    1     77
    Name: Embarked, dtype: int64
    • 위에서 간단하게 설명했던 데로 '라벨 인코더를 써서 0,1,2 로 숫자형으로 잘 바꾸었다. 하지만 이 데이터를 그대로 머신러닝을 시키게 되면 기계는 데이터 안에서 관계를 찾게 된다
      (예: 'S' = 2, 'Q' = 1 인데 Q+Q = S 구나 라고 학습해 버리게 된다)
    • 그렇기 때문에 독립적인 데이터는 별도의 컬럼으로 분리하고 각각의 컬럼에 대해 해당하는 값에만 특정 숫자를 부여해야한다. 이를 원 핫 인코딩 이라 부른다

     

    • 독립적으로 데이터를 처리하고 각각의 컬럼에 해당값에만 True 나머지는 False를 갖도록 해보자
    # 원핫인코딩전에는 반드시 더미 데이터가 필요하다
    pd.get_dummies(train['Embarked_num'][:6])

    컬럼 S C Q

    # 변수화
    one_hot = pd.get_dummies(train['Embarked_num'][:6])
    
    one_hot.columns = ['C','Q','S']
    one_hot

    • 위와 같이 컬럼을 분리시켜 카테고리형 -> 수치형으로 변환하고 그에 따라 생기는 수치형 값의 관계를 끊어주서어 독립적인 형태로 바꿔야 한다

     

     

    07 정규화(Normalization)

    • 컬럼간에 다른 min,max 값을 가지는 경우 정규화를 통해 최소치/최대값의 척도를 맞추는 것
    • 영화 평점을 예로 진행해보자. 네이버는 0~10점 기준, 넷플릭스는 0~5점 기준으로 영화평점을 준다 가정하고 네이버에서는 6점, 넷플릭스에서는 5점일때 그 영화는 과연 네이버 기준 형편없는 영화일까? 같은 영화임에도 이렇게 다르게 데이터가 있을 수 있다. 이에대한 척도를 맞추는게 정규화이다. 
    # 네이버 영화 평점 (0~10점) : [2,4,6,8,10]
    # 넷플릭스 영화 평점 (0~5점) : [1,2,3,4,5]
    
    movie = {'naver':[2,4,6,8,10], 'netflix':[1,2,3,4,5]}
    
    movie = pd.DataFrame(data=movie)
    movie

    ▶ 정규화 패키지 이용

    # 정규화 패키지 MinMaxScaler
    from sklearn.preprocessing import MinMaxScaler
    
    min_max_scaler = MinMaxScaler()
    
    min_max_movie = min_max_scaler.fit_transform(movie) #.fit_transform() 을 통해 학습하고 처리
    
    pd.DataFrame(min_max_movie, columns=['naver','netflix'])

     

     

     

    08 정규화(Standardization)

    • 평균이 0, 표준편차가 1이 되도록 변환해주는 작업
    # 평균이 0, 표준편차가 1이 되도록 변환
    from sklearn.preprocessing import StandardScaler
    standard_scaler = StandardScaler()
    
    # 샘플 데이터
    x = np.arange(10)
    # outlier 추가
    x[9] = 1000
    
    x.mean(), x.std()
    (103.6, 298.8100399919654)
    
    
    scaled = standard_scaler.fit_transform(x.reshape(-1,1)) #.reshape(-1, 1) 한컬럼에 하나만
    
    scaled.mean(), scaled.std()
    (4.4408920985006264e-17, 1.0) <- 작은값일때는 0으로 나오지 않음
    
    round(scaled.mean(), 2), scaled.std()
    (0.0, 1.0)
Designed by Tistory.