TIL/머신러닝

데이터 프로세스 : 데이터 전처리, EDA

jojoon2786 2024. 8. 16. 20:11

예측 모델링 프로세스

 

1. 데이터 수집

데이터 수집 단계는 예제 데이터 혹은 회사 데이터로 진행되기 때문에, 지나치는 경우가 많다.

하지만 적재돼있는 데이터가 없는 회사거나 수집이 필요한 경우가 생길 수 있다.

  1. Data Source
    • OLTP Database: OnLine Transaction Processing 은 온라인 뱅킹,쇼핑, 주문 입력 등 동시에 발생하는 다수의 트랜잭션(데이터베이스 작업의 단위) 처리 유형
    • Enterprise Applications: 회사 내 데이터 (ex 고객 관계 데이터, 제품 마케팅 세일즈)
    • Third - Party: Google Analytics와 같은 외부소스에서 수집되는 데이터
    • Web/Log: 사용자의 로그데이터
  2. Data Lake: 원시 형태의 다양한 유형의 데이터를 저장
  3. Data Warehouse: 보다 구조화된 형태로 정제된 데이터를 저장
  4. Data Marts: 회사의 금융, 마케팅, 영업 부서와 같이 특정 조직의 목적을 위해 가공된 데이터
  5. BI/Analytics: business Intelligence(BI)는 의사결정에 사용될 데이터를 수집하고 분석하는 프로세스

실제 데이터 수집은 어떻게 이루어지는가 ?

  • 회사 내 데이터가 존재한다면 ?
    • SQL 혹은 Python 을 통해 데이터 마트를 생성
  • 회사 내 Data가 없다면 ? → 데이터 수집 필요
    • 방법1: CSV, EXCEL 파일 다운로드
    • 방법2: API를 이용한 데이터 수집
    • 방법3: Data Crawling

2. 탐색적 데이터 분석(EDA)

EDA란?

  • 데이터의 시각화, 기술통계 등의 방법을 통해 데이터를 이해하고 탐구하는 과정임.

 

기술통계를 통한 EDA 예시

1) tips.describe()

  • include='all' 옵션을 통해 범주형 데이터도 확인 가능

> seaborn 라이브러리의 tips 데이터셋 describe() 결과

 

실습

seaborn 라이브러리의 tips 데이터셋을 통해 EDA를 실습해보자.

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

 

tips_df = sns.load_dataset('tips')

 

tips 데이터가 잘 불러와진 것을 볼 수 있다.

 

tips_df.describe(include = 'all')

 

기술통계에서 배웠던, describe이다.

기본적으론 수치형 데이터만 나오지만, 범주형 데이터의 최빈값 등을 확인하고싶을 땐 include = 'all'을 사용

 

 

시각화

1. countplot

  • 범주형 자료의 빈도 수 시각화
  • 범주형 데이터의 각 카테고리별 빈도 수
  • x축 : 범주형 자료, y축 : 빈도 수
# countplot x: 범주형 데이터, 관측치 : 개수

sns.countplot(data = tips_df, x = 'day')

countplot

 

2. barplot

  • 범주형 자료의 시각화
  • 범주형 데이터의 각 카테고리에 따른 데이터의 평균을 비교
  • x축 : 범주형 자료, y축 : 연속형 자료
# barplot x: 범주형 데이터, y: 연속형 데이터의 평균

sns.barplot(data = tips_df, x = 'sex', y = 'tip')

barplot

 

3. boxplot

  • 수치형 & 범주형 자료의 시각화
  • 데이터의 분포, 중앙값, 사분위 수, 이상치 등을 한눈에 표현
  • x : 수치형 or 범주형
  • y : 수치형 자료
sns.boxplot(data = tips_df, x='time', y='total_bill')

boxplot

 

4. histogram

  • 수치형 자료 빈도 시각화
  • 연속형 분포를 나타내고 싶을 때, 데이터가 몰려있는 구간을 파악하기 쉽다.
  • x축 : 수치형 자료, y축 : 자료의 빈도 수
sns.histplot(data=tips_df, x='total_bill', bins =20)

 

5. scatterplot

  • 수치형끼리 자료의 시각화
  • 방법 : 두 연속형 변수간의 관계를 시각적으로 파악하고 싶을 때
  • x축 : 수치형 자료
  • y축 : 수치형 자료
# x: 수치형 데이터
# y: 수치형 데이터

sns.scatterplot(data=tips_df, x='total_bill', y='tip')

 

6. pairplot

  • 모든 변수에 대한 시각화
  • 한 번에 여러 개의 변수를 동시에 시각화 하고 싶을 때
  • x축 : 범주형 or 수치형 자료
  • y축 : 범주형 or 수치형 자료
  • 대각선 : 히스토그램(분포)

pairplot

> 대각선 자료들은 똑같은 값이기 때문에 무조건 우상향 산점도 그래프가 나온다. 따라서 histogram으로 대체된다.

 

3. 데이터전처리

1) 이상치

이상치란 ? 

  • 관측된 데이터 범위에서 많이 벗어난 아주 작은 or 큰 값

두 가지 기준이 있음.

 

1. Extreme Studentized Deviation(ESD) 이용한 이상치 발견

  • 데이터가 정규분포를 따른다고 가정할 때, 평균에서 표준편차의 3배 이상 떨어진 값
    • 모든 데이터가 정규 분포를 따르지 않을 수 있기 때문에 다음 상황에서는 제한됨
      • 데이터가 크게 비대칭일 때( → Log변환 등을 노려볼 수 있음)
      • 샘플 크기가 작을 경우

 

2. IQR(Inter Quantile Range)를 이용한 이상치 발견

  • ESD와 동일하게 데이터가 비대칭적이거나 샘플사이즈가 작은 경우 제한됨.

  • Box plot : 데이터의 사분위 수*를 포함하여 분포를 보여주는 시각화 그래프, 상자-수염 그림이라고도 함.
  • 사분위 수 : 데이터를 순서에 따라 4등분 한 것

 

2) 이상치 발견 방법

  • ESD를 이용한 처리
import numpy as np
mean = np.mean(data)
std = np.std(data)    #표준편차
upper_limit = mean + 3*std
lower_limit = mean - 3*std
  • IQR을 이용한 처리(box plot)
Q1 = df['column'].quantile(0.25)
Q3 = df['column'].qunatile(0.75)
IQR = Q3 - Q1
uppper_limit = Q3 + 1.5*IQR
lower_limit = Q1 - 1.5*IQR
  • 조건필터링을 통한 삭제(boolean indexing) :  df[ df['column'] > limit_value]

(참고) 이상치는 주관적인 값이기 때문에, 그 데이터를 삭제 할지 말지는 분석가가 결정할 몫입니다.

다만, 이상치는 도메인과 비즈니스 맥락에 따라 그 기준이 달라지며 데이터 삭제 시 품질은 좋아질 수 있지만 정보 손실을 동반하기 때문에 이상치 처리에 주의해야 합니다.

 

이상치 처리 실습

#1 ESD 이상치 처리

# ESD 이상치 처리
import numpy as np
mean = np.mean(tips_df['total_bill'])
std = np.std(tips_df['total_bill'])
upper_limit = mean + 3*std
lower_limit = mean - 3*std

 

cond = tips_df['total_bill'] > upper_limit
cond

boll 자료형의 형태

 

 

> 적용  df[cond]

tips_df[cond]

 

#2 IQR 이상치 처리

sns.boxplot(tips_df['total_bill'])

box plot 으로 바로 확인한다.

boxplot

 

Q1 = tips_df['total_bill'].quantile(0.25)
Q3 = tips_df['total_bill'].quantile(0.75)
IQR = Q3 - Q1
upper_limit2 = Q3 + 1.5*IQR
lower_limit2 = Q1 - 1.5*IQR

 

적용

cond2 = tips_df['total_bill'] > upper_limit2 tips_df[cond2]

 

결측치

결측치란 ?

  • 존재하지 않는 데이터(null or NaN)

처리방법

수치형 데이터

  • 평균 값 대치 : 대표적인 대치 방법
  • 중앙값 대치 : 데이터에 이상치가 많아 평균 값이 대표성이 없다면 중앙 값을 이용

범주형 데이터

  • 최빈값 대치
  • 사용 함수
    • 간단한 삭제 & 대치
      • df.dropna(axis = 0): 행 삭제
      • df.dropna(axis = 1): 열 삭제
      • Boolean Indexing
      • df.fillna(value): 특정 값으로 대치(평균, 중앙, 최빈값)
    • 알고리즘을 이용
      • sklearn.impute.SimpleImputer:평균, 중앙, 최빈값으로 대치
        • SimpleImputer.statistics_ : 대치한 값 확인 가능
      • sklearn.impute.IterativeImputer: 다변량대치(회귀 대치)
      • sklearn.impute.KNNImputer: KNN 알고리즘을 이용한 대치

 

titanic 데이터를 이용하여 실습해보자.

 

데이터 불러오기

titanic_df = pd.read_csv("C:/Users/jojoo/OneDrive/바탕 화면/sparta_python/titanic/train.csv",encoding = 'utf-8') titanic_df.head(3)

 

info() 결측치 확인

titanic_df.info()

 

Age 컬럼의 결측치를 삭제해보자

#1 dropna

# Age 컬럼 결측치 대치
titanic_df.dropna(axis = 0).info()    # 데이터 실종이 심각

axis = 0  >> 행기준 날림

 

891 > 183으로 데이터 손실이 심각하다는 것을 알 수 있음.

그렇다면 Age의 결측치만 없애려면 어떻게 하는게 좋을까?

 

>불리언 인덱싱 사용

# 불리언 인덱싱 사용 나이컬럼이 결측치인 값 확인
cond3 = titanic_df['Age'].isna()
titanic_df[cond3]

.isna() > 결측치인 값만 True 로 반환

 

# 불리언 인덱싱 사용 나이컬럼이 결측치가 아닌 값 확인
cond4 = titanic_df['Age'].notna()
titanic_df[cond4].info()

.notna() > 결측치가 아닌 값만 True로 반환

 

삭제가 아닌 결측치를 채워보자

Age의 평균으로 결측치를 채워주자

mean_age = titanic_df['Age'].mean().round(2)
titanic_df['Age_mean'] = titanic_df['Age'].fillna(mean_age)

titanic_df.info()

.fillna() > 결측치 값 () 안에 값으로 대치

 

SimpleImputer 을 이용하여 대치할 수도 있다.

from sklearn.impute import SimpleImputer

si = SimpleImputer()
si.fit(titanic_df[['Age']])

 

si.statistics_

결과 : array([29.69911765])

 

titanic_df['Age_mean_si'] = si.transform(titanic_df[['Age']])

titanic_df.info()

 

실습이기에 새로운 컬럼을 생성하여 거기에 데이터를 넣어주었지만, titanic_df['Age']에 할당해주면 결측치를 원래 데이터에서도 대치할 수 있다.