[2024.10.30] 필수 온라인 강의 Part15 Machine Learning Basic CH03 모델과 데이터
ML 프로젝트의 구성요소
- y는 따로 쓰는 곳이 있음 y = 정답라벨, 목표값, GT y^ = 모델의 출력값, 예측값 (hat은 추측값이라는 의미) |
데이터셋
함수의 입력값 x와, 그에 대응하는 라벨 y의 순서쌍을 1개 이상 모아둔 집합
- 머신러닝에서 학습을 한다는것
1. 정해진 parametric 함수, 즉 모델에서
2. 데이터의 인풋값에 대한 모델 예측값과 라벨의 차이로 계산되는 손실 함수를 최소화하는
3. 파라미터 θ를 찾아내는 것. - 다양한 머신러닝 방법론들은
어떤 구조의, 어떤 파라미터를 가진 모델을 사용하는가?
함수의 인풋/아웃풋은 어떤것인가?
어떤 손실 함수를 사용하는가?
데이터는 어떻게 주어지는가?
데이터의 다양한 형태와 도메인의 구분
데이터의 종류
- 정량적 정보
- 객관적, 자동화/표준화 가능
정성적 정보
- 재현가능성 낮음, 주관적 - 정형 데이터(Structured Data)
- 데이터를 표현하는 변수들이 의미를 가진 정량적 정보로, 주로 테이블 형태로 구조화되어있는 데이터셋
- 엑셀 스프레드시트
- CSV(Comma-Separated Values)파일
- 수치형 변수 (Numerical Variable)
- 양적(Quantitative) 변수라고도 하며, 평균값 등의 수치적 연산이 가능한 숫자 형태의 변수.
- 연속형 변수 : 나타내는 값이 실수로 표현되는 연속적인 수치
- 이산형 변수 : 정수로 표현되는 이산적인 수치
- 범주형 변수(Categorical Variable)
- 질적(Qualitative) 변수라고도 하며, 가능한 여러 범주들 중 하나(또는 여러개)를 고르는 형태로 표현되는 변수.
- 명목형 변수 : 각 항목들 사이에 순위를 매길수 없음
- 순위형 변수 : 각 항목들 사이에 순위를 매길수 있음
비정형 데이터(Unstructured Data)
- 변수들이 구조화되어있지 않은, 정성적 정보로 구성된 데이터셋.
- 텍스트
- 이미지, 동영상 등
- 음악, 녹음파일 등 - 범주형 데이터의 인덱싱(Indexing)
- 각 범주의 순서를 임의로 정해, 0번 부터 번호를 부여(indexing)하여 표현하는 방식
- 성별: 여성(0), 남성(1)
- 거주지역: 서울(0), 경기(1), 강원(2), 충청(3), 전라(4), 경상(5), 국외(6)
- 영어 알파벳: a(0), b(1), … z(25) - 데이터의 수치적 표현방법
- 텍스트 데이터의 글자별(Character-level), 단어별(Word-level) 인덱싱
- 글자 수준 인덱싱
- 영어 알파벳: a(0), b(1), … z(25), A(26), ... Z(51)
- cat: [2, 0, 19]
- Hello, World: [33, 4, 11, 11, 14, … 3]
- 단어 수준 인덱싱
- Hello, World: [?, ?]
- 자연어처리(NLP, Natural Language Processing)
- 이런 방식으로 텍스트 정보를 주로 연구, 분석하는 도메인
- 비트맵(Bitmap)
- 빛의 3원색인 빨강, 초록, 파랑색(RGB)의 강도를 0~255사이 정수로 나타내어 색상을 길이 3의 벡터로 표현하고, 이를 이미지의 해상도 (가로길이x세로길이)만큼 쌓아 전체 이미지를 표현하는 방식.
- 동영상의 경우는 이미지 데이터를 여러장 겹친것으로 이해할 수 있다. (일반적으로 영상 1초 마다 24~60장)
- 컴퓨터 비전(Computer Vision)
- 이미지나 동영상 데이터를 주로 다루는 머신러닝의 연구분야.
- Raw Wave
- 표현방법 마이크에서 들어오는 (-1에서 1사이의) 음성 신호를 일정 주기(sampling rate)로 샘플링하여 저장한 형태의 데이터.
- 보통 샘플링은 1초당 44,100번(44.1kHz) 또는 48,000번(48kHz)씩 진행한다.
- 스펙트로그램(Spectrogram)
- 푸리에 변환(Fourier Transform)을 사용해 음성 신호를 시간에 따른 주파수(소리의 높낮이)대역별 신호의 세기로 나타낸 것.
- 음성처리(Speech Processing, Sound Processing)
- 음성이나 음악 등의 소리 데이터를 주로 다루는 머신러닝의 분야.
- 추천시스템(Recommender System)
- 개인의 관심사에 맞는 컨텐츠를 제공하는 방법에 대해 연구하는 머신러닝의 분야로, 다양한 형태의 정형, 비정형 데이터를 함께 다룬다
- 유저가 남기는 평점, 좋아요/싫어요 등 피드백 정보,
- 웹페이지 방문 기록, 구매 기록 등
데이터의 품질과 EDA
- 좋은 데이터
좋은 성능의 모델을 학습할 수 있는 데이터
- 다양한 인풋에서 학습할수 있도록 다양성이 크고
- 모델 성능을 떨어뜨리는 노이즈가 적은 데이터셋이 필요 - 데이터셋의 다양성(Diversity, Coverage)
- 데이터셋이 커버하지 못하는 부분이 있다면 데이터셋 편항(Bias)이 생겨 전체의 경향성을 파악이 불가 - 데이터 노이즈
- 데이터의 노이즈가 있는 경우 함수 정의 자체가 모호해지거나, 불연속 함수가 되어 성능이 떨어짐
- 결측치 : 데이터 내에 아예 비어있는 값
- 측정 자체가 안됨
- 저장/변환과정에서 정보가 손상
- 데이터셋을 읽어올 때 테이블 구조를 잘못 파싱하는 등
- 이상치
- 이론상 가능한 범위를 벗어나 있음
- 정상 분포에서 크게 벗어난 값.
- 틀린 라벨
- 단순 실수로 라벨링이 잘못된 경우
- 문제 자체가 너무 어려워서 사람이 보아도 정확한 정답이 어떤 것인지 고르기 쉽지 않은 경우
- 문제 정의의 모호성
- 사람이 봐도 어느쪽이 정답인지 의견이 갈리는 경우
- 중복 샘플
- 데이터셋에 똑같은 입력값을 가진 샘플이 여러번 들어있는 경우
- 서로 다른 라벨이 붙어있다면 더 큰 문제를 일으킴
- 도메인 외의 샘플( out of domain 데이터)
- 모델에서 다루려고 하는 대상이 아닌 것들이 인풋으로 들어오는 경우
( 사람 얼굴 사진 데이터에 섞여있는 손그림, 한국어 → 일본어 번역 데이터에 끼어있는 영어문장) - Silent Failure (조용한 실패)
- 모델의 학습을 실행했을 때, 코드가 에러 없이 잘 돌아가고 손실함수 값도 정상적으로 떨어지는것처럼 보이지만
- 학습이 완료되고 평가를 해보면, 전혀 사용할 수 없는 수준의 성능을 보이는 경우
- 문제가 있다는 사실조차 긴 시간이 지나야 파악이 가능 -> 전체 프로젝트의 진행이 크게 지연 - 노이즈 처리를 통한 좋은 데이터 만들기
- 수시로 EDA를 통해 데이터를 들여다보며 노이즈를 확인, 정제
- 모델의 성능이 이상하게 나오는 경우, 원인을 분석하여, 발생할 수 있는 노이즈의 샘플들을 수집, 분류 - 데이터셋 라벨링 기준의 설정
- 애매한 샘플에 대해서는 명확하고 구체적인 라벨링의 기준(가이드라인)을 설정
- 데이터셋 전체에 일관성있게 적용 - 모호한 데이터의 처리
- 개별 샘플을 어느쪽으로 처리하는지보다는 전체 데이터셋에 일관성있는 기준을 적용
- 모호한 케이스들을 보며 구체적이고 명확한 기준을 설정 - EDA (Exploratory Data Analysis; 탐색적 데이터 분석)
- 데이터를 탐색함으로써 각 변수의 의미와 특성, 분포를 이해하는 과정
- 데이터에 대한 명확한 이해를 통해
- 정확한 문제 정의와 모델링을 가능하게 하고
- 빠르게 다양한 가설을 세워보고, 분석을 통해 검증하면서 문제의 정의와 접근방법을 고민
-> 데이터셋이 어떤 종류의 노이즈를 포함하는지 어떤 편향이 생길 수 있을지 파악하고 해결방법을 고민 - 데이터셋의 편향(Bias)
- 문제 정의에 포함되지만 데이터셋에는 없거나 매우 적은 종류의 샘플들이 있는 확인
- 있다면, 어떻게 해결할 수 있을지 고민해 데이터 수집 및 정제 과정을 개선
- 생존자 편향 - EDA (탐색적 데이터 분석)
- 데이터셋의 기본적인 정보를 파악
- 샘플을 랜덤추출해보며 패턴 파악
- 각 변수의 통계량, 분포 확인
- 변수간의 관계 파악 등의 과정을 진행
- 노이즈나 편향에 대한 분석도 수시로 진행 - EDA의 진행 과정
1. 데이터의 기본적인 정보 파악 데이터셋을 열어 다음과 같은 기본적인 정보들을 파악
- 데이터 전체의 샘플 수, 활용할수 있는 변수(피쳐)의 수와 종류
- 각 변수가 주어지는 형태와 데이터타입 (범주형? 수치형?)
- 수치형 변수라면, 이론상 나올수 있는 수치의 범위는?
- 범주형 변수라면 가능한 범주들은 어떤 것인가?
- 비정형으로 주어지는 변수가 있는가?
- 이 과정에서 확인할수 있는 형태의 노이즈
- 각 변수가 결측치를 포함하는지 여부
- 이론상 가능한 범위를 벗어나는 값 (가격 정보인데 음수가 존재하는 경우 등)
2. 이상치와 결측치의 파악
- 데이터 내 결측치나 이상치가 없는지 확인하여 분석 과정에서 생길 문제를 사전에 방지
- NULL, NaN등의 결측치가 왜 생겼는지, 원인을 파악해 처리방식을 고민
- 데이터의 전반적인 특성에서 어긋난 이상치가 있는지를 확인
- Overflow
- 숫자에는 한계가 없지만, 컴퓨터는 정해진 자릿수의 2진법 표현으로 숫자를 저장하므로 다룰 수 있는 숫자의 범위에 한계
- int32(32비트 정수)타입이 저장할 수 있는 가장 큰 수는 2,147,483,647 : 이 이상이면 음수로 표현되는 현상이 있었다. - 박스플롯(boxplot)
- 데이터의 이상치를 파악하는데 유용한 시각화 방법. 다음 5개의 요약 통계량을 하나의 박스와 선으로 표현
- 박스플롯의 수염(whisker) : 박스의 높이 (Q3 - Q1)을 IQR, Q1 - 1.5*IQR에서 Q3 + 1.5*IQR까지의 범위를 벗어난 데이터 샘플. 이상치일 가능성이 큼
- 박스 플롯의 최대/최소값은 실제 모든 데이터의 최대/최소값이 아니라, 수염 부분을 이상치로 간주하고 이를 제외한 나머지 값들의 최대/최소값을 나타냄 - 변수별 통계량과 분포 확인
- 데이터의 분포를 확인함으로써 통계량의 의미에 대하여 명확한 이해 가능
- 비대칭도(왜도; skewness): 데이터 분포가 비대칭인 정도. 분포가 한쪽에 치우칠수록 절대값이 큼
- 첨도(kurtosis): 데이터 분포가 뾰족한 정도. 샘플의 분포가 한곳에 몰려있지 않고 퍼져있을수록 값이 작음 - 상관계수 (Correlation) : 데이터 변수 간 선형적인 연관성(상관관계)이 있는지를 나타내는 지표
상관행렬 그림 (Correlation plot) : 데이터셋 내 모든 변수간의 상관관계를 한개의 행렬로 나타낸 것.
- x축과 y축에 각 변수를 나열하고, 변수 간 상관계수를 색상으로 표현하여 하삼각행렬(lower triangular matrix)로 표현 - 데이터셋 전처리
- 목적
- EDA 과정에서 발견된 데이터 노이즈를 제거
- 모델이 잘 학습할 수 있는 형태로 데이터를 변환
- 이상치 및 결측치의 처리
- 이상/결측치를 포함하는 샘플을 제거하기
- 이상/결측치를 포함하는 변수를 제거하기
- 이상/결측치를 다른값으로 대체하기
( 주변의 다른 샘플/변수의 값, 변수의 평균/중앙값 등 전체 통계량, 변수의 의미상 적절한 값(0 등))
- 피쳐 스케일(scale)의 조정
- 스케일 조정은 변수의 크기를 조정하는것으로, 분포의 모양 자체는 변하지 않음
- 표준화(Standardization) : 변수의 평균이 0, 표준편차가 1이 되도록 변환
- 정규화(Normalization, Min-Max Scaling) : 변수의 최솟값, 최댓값이 각각 0, 1(경우에 따라 -1, 1)이 되도록 변환
EDA 실습
- 데이터 불러오기
import numpy as np
import pandas as pd
import sklearn.datasets as D
- YouTube Statistics 데이터 분석 : YouTube 상위 채널의 통계자료에 대한 데이터셋
!head -3 "Global YouTube Statistics.csv" # 터미널 명령어의 앞에 !를 붙여 셀 내에서 실행
- csv 파일 : Comma Separated Values라는 이름처럼 콤마(,)로 나뉘어진 값들을 나열한 파일
- 사용방법이 매우 간단하고 별다른 어려움 없이 직관적으로 해석
- 테이블 형태의 데이터를 저장하는데에 자주 사용되는 포멧
data = pd.read_csv('Global YouTube Statistics.csv', encoding='latin1') # 데이터 불러오기
- 인코딩 형식이 일반적으로 사용되는 utf-8이 아니라 latin-1 : encoding="latin-1" 파라미터를 추가로 전달
- UnicodeDecodeError와 같은 에러가 발생해 파일을 읽어오지 못하거나, 파일의 내용 일부가 손상되어 이후 분석을 방해
data # 데이터 확인하기
- 데이터가 잘 읽어와졌는지 확인
- 데이터 살펴보기
- 전체 샘플의 수나 변수의 개수와 같이 매우 간단한, 기본적인 정보들을 확인하는것으로 시작
- 점차 각 변수의 분포, 여러 변수들 상호간의 상관관계같은 고수준의 정보를 확인
- 분석과정에 에러를 일으키거나 방해가 될수 있는 요소들을 확인
- 모델링을 시작하기 전에 제거하거나 별도 전처리를 통해 변환해주어야하는 부분 등을 확인
print(data.shape) # 데이터 크기 확인하기
- 샘플 수와 피쳐의 개수, 즉 데이터가 얼마나 많은 수의 샘플들을 포함하는지, 분석에 활용할 수 있는 변수는 몇 개인지 확인
- (995, 28) -> 995개의 데이터 포인트(행)과 28개의 변수(열)
data.columns # 데이터의 컬럼 이름 확인하기
- csv파일 내에 각 column
- 변수의 이름이 지정되지 않은 경우 여기에서 컬럼의 이름이 [0,1,2,...]로 나타나거나, 첫번째 데이터 샘플이 column의 이름으로 잘못 파싱되는 경우가 있음 : read_csv함수의 header 옵션을 수정해 문제를 해결
- 데이터 정보 확인
- 데이터 샘플 개수, 데이터 변수 개수, 데이터 변수 인덱스와 이름, 데이터 변수 타입
- 데이터 및 각 변수의 데이터 타입이 원하는대로 잘 정의되었는지 확인
* pandas 라이브러리의 info 메소드를 이용
data.info() # 데이터 정보 살펴보기
- null 데이터가 있는지, Dtype은 어떤지 확인을 하게 됨
- 동시에 확인하는 것도 좋지만, 각각의 feature 별로 하나하나 확인하는 방법
# 여러번 실행했을 때 같은 결과가 나오도록 랜덤 시드를 고정합니다.
np.random.seed(1234)
# 살펴볼 피쳐의 인덱스를 랜덤으로 선택합니다.
# feature_index = 6
feature_index = np.random.choice(len(data.columns))
print(f"피쳐 번호: {feature_index}")
# 데이터셋에서 인덱스에 해당하는 피쳐 이름을 가져오고, 이를 이용해 다시 데이터에서 피쳐를 선택
feature_name = data.columns[feature_index]
print(f"피쳐 이름: {feature_name}")
data[feature_name]
- 가능한 범주들은 몇개가 있는지, 또 어떤 범주들이 있는지 확인
feature_name = "channel_type" # 분석할 피쳐의 이름
unique_values = data[feature_name].unique() # 데이터를 가져와 중복값을 제거
print('범주:', unique_values)
print('범주 수:',len(unique_values))
- 각 범주에 속하는 샘플들이 몇개나 존재하는지 확인
data[feature_name].value_counts() # 각 범주 별로 샘플이 몇 개가 존재하는지 확인
- 임의의 샘플(row)을 골라 똑같이 육안으로 관찰
sample_index = np.random.choice(len(data)) # 임의의 샘플 선택
print(f"샘플 인덱스: {sample_index}")
data.iloc[sample_index] # 선택된 데이터 보기
정성 평가 과정
- 데이터 자체에 대한 이해도를 높일 수 있는 가장 쉬운 방법
- 이 단계만으로도 데이터셋의 수많은 의미있는 특성들을 파악
- 자동화, 정형화된 분석 프로세스로 알 수있는 정보에는 한계가 있을수 있음
- 전체적인 탐색과정 중간중간에도, 수시로 위 셀에서처럼 샘플이나 피쳐별로 직접 데이터를 확인해보는 과정을 수행
- 데이터 결측치 확인
- 데이터에 결측치(NULL, NA, NaN) 값이 있는지 확인
- 이러한 값이 존재하면 분석 과정에서 에러를 발생시키거나 결과에 악영향
- 데이터셋 내의 결측치가 어떤 맥락에서 등장하는지 대략적으로 파악해본 뒤에, 어떤 처리를 적용할지 결정
data.isnull() # 데이터 내 결측치가 있는지 확인하기
- 결측치인지를 한 눈에 보기 위해 각 변수별로 결측치가 몇 개인지 확인
- sum 메소드에는 데이터를 어떤 축으로 더할것인지를 지정하는 axis 옵션이 있고,
(별도로 지정하지 않을 경우 default로 axis=0옵션이 사용)
- axis=0을 지정, 주어진 데이터를 column-wise로, 즉 세로로 합치는 것 : 열, 피쳐별로 합계값을 확인
- axis=1을 지정, 행별 : 샘플별로 합계값을 확인
data.isnull().sum() # 데이터 내 NULL 값이 있는지 변수 별로 확인하기
sample_indices_with_nan = data.isnull().sum(axis=1) > 0 # 결측치를 하나라도 포함하는 행의 인덱스를 확인
data[sample_indices_with_nan] # 결측치를 하나라도 포함하는 행들을 확인
sample_indices_with_nan = data.isnull().sum(axis=1) >= 8 # 결측치를 "8개 이상" 포함하는 행의 인덱스를 확인
data_with_nans = data[sample_indices_with_nan] # 결측치를 "8개 이상" 포함하는 행들이 어떤것인지 확인해봅니다.
print(len(data_with_nans))
data_with_nans
# NA를 가진 feature들을 변수로 정의하여 확인합니다.
columns_with_nan = [
"Country",
"Abbreviation",
"Gross tertiary education enrollment (%)",
"Population",
"Unemployment rate",
"Urban_population",
"Latitude",
"Longitude"
]
# 위에서 선택한 8개 feature들이, 가설대로 모두 NaN인지 확인해봅니다.
data_with_nans[columns_with_nan].isnull().all(axis=1).sum()
- 음이 아닌 값을 가지는 변수 내에 음수값이 있는지 확인
(data['subscribers'] < 0).any()
- 위도(latitude)와 경도(longitude)에 따른 확인
# 위도와 경도 각 변수의 최솟값과 최댓값 확인
print(data[['Latitude','Longitude']].min())
print(data[['Latitude','Longitude']].max())
- 위도와 경도 변수의 최솟값(min)과 최댓값(max)를 비교해보면 모두 기대되는 범위 내에 값이 존재하는 것을 확인
- 데이터 요약 통계량 확인
- 최댓/최소값 이외에도 샘플 수, 평균, 표준편차, 중위수, 25%, 75% 값, IQR 등 유용한 데이터의 요약 통계량을 제공
- 요약통계량을 살펴보면 각 변수의 대략적인 분포를 확인
data.describe() # 데이터 요약통계량 보기
- 시각화를 위한 패키지
import matplotlib.pyplot as plt
import seaborn as sns
- 데이터 이상치 확인
- 데이터에 포함된 이상치를 파악해보기 위해 Box Plot 시각화를 사용
target_feature = 'lowest_monthly_earnings' # boxplot을 확인할 변수를 선택
# boxplot 보기
sns.boxplot(data=data, y=target_feature) # seaborn(sns) 패키지를 이용해 boxplot 그리기.
plt.show() # 그림 보여주기
- 이상치는 일반적으로 Q3+IQR 보다 크거나 Q1-1.5*IQR보다 작은 데이터
# 이상치 제거를 위한 분위수 확인하기
Q3 = data['lowest_monthly_earnings'].quantile(q=0.75) # 75% 분위수
Q1 = data['lowest_monthly_earnings'].quantile(q=0.25) # 25% 분위수
IQR = Q3-Q1
print(Q1, Q3, IQR)
- 변수의 분포 확인 - 히스토그램, 막대그래프
- 히스토그램 보기
sns.histplot(data=data, x=target_feature) # 히스토그램 그리기, kde 옵션은 막대 뿐만 아니라 밀도 형태의 선으로도 보여주는 것
plt.show() # 그림 보여주기
- 꼬리가 긴 분포를 가진 변수의 히스토그램을 로그스케일로 확인하기.
sns.histplot(data=data, x=target_feature, log_scale=(False, True))
plt.show() # 그림 보여주기
- 막대 그래프
# 막대그래프의 막대로 범주를 확인할 변수
category_feature = 'category'
# 막대그래프의 높이로 값을 확인할 변수
target_feature = 'lowest_monthly_earnings'
# 막대그래프 생성
barplot = sns.barplot(data=data, x=category_feature, y=target_feature, color='C0', errorbar=None)
# matplotlib에서 x축 레이블의 위치, 방향 설정을 변경합니다.
loc, labels = plt.xticks()
barplot.set_xticklabels(labels, rotation=90)
plt.title('Lowest Monthly Earnings per each category')
plt.show()
- 변수 간 관계 확인 - 상관행렬그림
- 상관계수는 두 변수가 함께 움직이는 경향성
- 상관행렬(correlation matrix)은 데이터셋에 포함된 모든 변수들의 쌍에 대해서 상관계수를 측정하고 이를 행렬
- 상관관계의 강도를 -1에서 1사이의 수치로 나타낸 지표
- 두 변수의 순서를 바꾸어도 변하지 않으므로 상관행렬은 대칭행렬로 나타나고, 상관행렬에서 대각원소는 자기 자신과의 상관계수로 무조건 1.0이 되어 의미가 없는 수치
- 상관계수가 아예 1.0이나 -1.0인 변수들은, 실제로 매우 강한 상관관계를 가지는 의미있는 변수일 가능성이 없지는 않지만, 그보다는 독립적으로 다룰 수 없는 변수일 가능성이 훨씬 높음
- 한 변수가 다른 변수와 사실상 같은 값으로 표현되어버리는 경우 두 변수는 공선성(Colinearity)이 있다
-> 비슷하게 한 변수가 평균값 등 다른 여러 변수의 조합으로 나타나는 경우는 다중 공선성(Multicolinearity)
- 상관행렬에서 상관계수가 1.0 또는 -1.0으로 나타나는 변수들은 이렇게 공선성이나 다중공선성을 가진 변수일 가능성이 큼
- 변수들 사이의 공선성이나 다중공선성이 나타나는 경우에는, 관련 변수를 제거하여 모든 변수가 독립적으로 다루어지도록 만드는 방법사용
# 데이터의 상관계수 행렬을 생성
corr = data.corr(numeric_only=True) # 데이터셋으로부터 각 변수별 상관계수를 계산하여 행렬형태로 나타내는 함수. 여기서는 피어슨 상관계수를 이용
# numeric_only는 숫자형 변수만 상관계수를 계산하도록 하는 옵션
# figure에서 생략될 부분을 지정하는 mask 행렬을 생성 - 실제로는 mask 없이 다 생성해도 괜찮습니다.
mask = np.ones_like(corr, dtype=bool)
mask = np.triu(mask)
# 시각화될 그림의 크기를 지정
# 히트맵 형태로 상관행렬 시각화하기
plt.figure(figsize=(13,10))
sns.heatmap(data=corr, annot=True, fmt='.2f', mask=mask, linewidths=.5, cmap='RdYlBu_r')
plt.title('Correlation Matrix')
plt.show()
- 데이터 전처리 - 결측치 처리
- NaN샘플을 가진 데이터 샘플들을 분석대상이 아니라 판단해 제거
# 분석을 완료한 데이터 샘플 123개의 인덱스 확인
indices_to_keep = data.isnull().sum(axis=1) < 8
# 샘플을 제거. 비교를 위해 원본 데이터는 별도로 복사해둠.
data_original = data
data = data[indices_to_keep].copy()
print(f"데이터 샘플 수 변화: {len(data_original)} -> {len(data)}")
# 나머지 결측치중 가장 많은 비중을 차지하는 subscribers_for_last_30_days에서 NaN을 0으로 대체
data["subscribers_for_last_30_days"].fillna(0, inplace=True)
# 나머지 결측치를 포함하는 모든 행들은 버림(drop). axis=0일 경우 결측치가 있는 행을, axis=1이면 열을 전부 제거한다.
data.dropna(axis=0, inplace=True)
print(f"처리 완료 후 데이터 샘플 수: {len(data)}")
# 결측치가 잘 제거되었는지 확인
data.isnull().sum()
- 데이터 분포 변환
- 'lowest_monthly_earnings' 의 분포가 오른쪽으로 너무 꼬리가 길어 왼쪽으로 치우쳐진 것을 확인
- 우리가 원하는 분포의 형태로 관측된 데이터의 분포를 변환
- 변수를 해석할 때는 변환을 적용했다는 사실을 충분히 고려하여야하며, 필요한 경우 변환 이전의 데이터로 되돌려 사용
# 데이터 분포 변환을 위한 scikit-learn 패키지 내 함수 불러오기
from sklearn.preprocessing import scale
- 다음과 같이 꼬리가 길어 치우친 분포(long-tail, skewd)를 정규분포에 가깝게 하기 위해 log scale로 변환
# 로그변환을 진행할 변수를 선택합니다. 여기에서 다른 피쳐를 지정하면 다른 피쳐에도 로그변환을 진행해볼 수 있습니다.
target_feature = 'lowest_monthly_earnings'
# 데이터 로그 변환
# 로그 스케일로 변환한 값으로 새 변수를 만듭니다. 새 변수명은 기존 변수명에 prefix를 붙입니다.
data[f'log_{target_feature}'] = scale(np.log(data[target_feature]+1)) # log에 0값이 들어가는 것을 피하기 위해 1을 더해줍니다.
# 로그변환한 변수의 요약통계량 보기
data[f'log_{target_feature}'].describe()
- 변환 전후 데이터 요약 통계량 비교하기
data[[target_feature, f'log_{target_feature}']].describe()
# 데이터 분포 변환 전후를 비교하기 위해 2개의 plot 지정
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(15, 6))
# 히스토그램으로 변환 전 데이터의 분포 보기
sns.histplot(data=data, x=target_feature, kde=True, ax=ax[0])
ax[0].set_title('Before log transformation')
# 히스토그램으로 변환 후 데이터의 분포 보기
sns.histplot(data=data, x=f'log_{target_feature}', kde=True, ax=ax[1])
ax[1].set_title('After log transformation')
plt.show()
- 데이터 단위 변환
- 각 변수를 비슷한 스케일로 변환
- 데이터 내 각 변수의 스케일을 균등하게 만들기 위해, 표준화(Standardization)와 정규화(Normalization)를 통한 데이터 단위 변환을 사용
- 표준화(Standardization) : 데이터의 분포를 평균이 0이고 분산이 1이 되도록 변환하는 것
- 정규화(Normalization 혹은 minmax scaling) : 데이터를 최솟값이 0이고 최댓값이 1로, 0에서 1사이의 값을 가지도록 변환하는 방법
# 데이터 분포 변환을 위한 scikit-learn 패키지 내 함수 불러오기
from sklearn.preprocessing import StandardScaler, MinMaxScaler
- 표준화(Standardization)을 이용하여 데이터의 단위를 변환
# 스케일링을 진행할 변수를 선택합니다. 여기에서 다른 피쳐를 지정하면 다른 피쳐에도 표준화를 진행해볼 수 있습니다.
target_feature = 'lowest_monthly_earnings'
# scikit-learn패키지를 활용한 standardization
standard_scaler = StandardScaler()
data[f'standardized_{target_feature}'] = standard_scaler.fit_transform(data[[target_feature]]) # 표준화한 데이터를 새로운 변수에 저장하기
# 비교를 위해 변환 전후의 피쳐를 선택
feature_original = data[target_feature]
feature_standardized = data[f'standardized_{target_feature}']
# 변환 전후의 평균, 표준편차 비교
print(f"평균(mean)비교: {feature_original.mean():.7} -> {feature_standardized.mean():.7}")
print(f"표준편차(standard deviation)비교: {feature_original.std():.7} -> {feature_standardized.std():.7}")
- 평균(mean)과 표준편차(std)가 각각 0, 1의 값으로 변환된 것을 확인
- 표준화와 정규화는 분포의 모양 자체를 변화시키는것은 아니므로 그래프의 모양은 완전히 동일하게 나타남
# 데이터 단위 변환 전후 비교
fig, ax = plt.subplots(nrows=1,ncols=2,figsize=(15,6)) # 데이터 단위 변환 전후를 비교하기 위해 2개의 plot 지정
# 히스토그램으로 변환 전 데이터의 분포 보기
sns.histplot(data=data, x=target_feature, kde=True, ax=ax[0])
ax[0].set_title('Before standardization')
# 히스토그램으로 변환 후 데이터의 분포 보기
sns.histplot(data=data, x=f'standardized_{target_feature}', kde=True, ax=ax[1])
ax[1].set_title('After standardization')
plt.show()
- 정규화(Normalization)는 다음과 같이 수행
# 스케일링을 진행할 변수를 선택합니다. 여기에서 다른 피쳐를 지정하면 다른 피쳐에도 표준화를 진행해볼 수 있습니다.
target_feature = 'lowest_monthly_earnings'
# scikit-learn패키지를 활용한 normalization
normalized_scaler = MinMaxScaler()
data[f'normalized_{target_feature}'] = normalized_scaler.fit_transform(data[[target_feature]]) # 표준화한 데이터를 새로운 변수에 저장하기
# 비교를 위해 변환 전후의 피쳐를 선택
feature_original = data[target_feature]
feature_normalized = data[f'normalized_{target_feature}']
# 변환 전후의 최대, 최소값 비교
print(f"최소값(min) 비교: {feature_original.min():.7} -> {feature_normalized.min():.7}")
print(f"최대값(max) 비교: {feature_original.max():.7} -> {feature_normalized.max():.7}")
- 데이터 요약 통계량을 보니, 최솟값이 0이고 최댓값이 1인 분포로 변환된 것을 확인
- 표준화와 마찬가지로 그래프의 모양 자체는 변화하지 않음
# 데이터 단위 변환 전후 비교
fig, ax = plt.subplots(nrows=1,ncols=2,figsize=(15,6)) # 데이터 단위 변환 전후를 비교하기 위해 2개의 plot 지정
# 히스토그램으로 변환 전 데이터의 분포 보기
sns.histplot(data=data, x=target_feature, kde=True, ax=ax[0])
ax[0].set_title('Before normalization')
# 히스토그램으로 변환 후 데이터의 분포 보기
sns.histplot(data=data, x=f'normalized_{target_feature}', kde=True, ax=ax[1])
ax[1].set_title('After normalization')
plt.show()
'Study > 머신러닝' 카테고리의 다른 글
머신러닝 BASIC _ 모델 평가와 개선 (3) | 2024.11.04 |
---|---|
머신러닝 BASIC _ 다양한 데이터 처리 (13) | 2024.11.01 |
머신러닝 BASIC _ 비지도학습 방법론 (2) | 2024.10.31 |
머신러닝 BASIC _ 지도학습 방법론 (4) | 2024.10.30 |
머신러닝 BASIC _ 머신러닝이란? (8) | 2024.10.29 |