데이터 전처리 01

이서영·2023년 8월 24일
0

전처리

목록 보기
1/1

데이터 전처리란

데이터 전처리

  • 데이터 분석과 머신러닝 모델 구축의 성공을 위해 핵심적인 단계이며, 데이터를 가공하고 정리하는 과정

  • 데이터의 결측치 및 이상치를 확인하거나 제거하고, 불일치 되는 부분을 일관성 있는 데이터의 형태로 전환하는 과정

  • 왜곡된 분석을 방지하기 위해서 분석에 적합하게 데이터를 가공해 품질을 올리는 과정

  • 기본 전처리 과정

      1. 데이터 이해 : 데이터의 종류 및 구조, 변수들과의 관계를 이해
      1. 데이터 클랜징 : 결측치, 중복 데이터, 이상치 등을 처리
      • 1-1. 결측치 확인(결측치 정보 확인) -> 컬럼별 결측치 정보 확인
        -> 결측치 처리
      • 1-2. 중복 데이터 확인 및 처리
      • 1-3. 이상값 처리
      1. 데이터 변환(인코딩) : 범주형 데이터를 수치형으로 변환하거나 텍스트를 벡터로 변환. 데이터를 모델에 입력 가능한 형태로 변환 (토큰화 등이 있다.)
      1. 정규화 및 스케일링 : 범주형 데이터를 모델에 입력가능한 형태로 변환
      1. 특성 선택 및 추출 : 데이터에는 불필요한 특성이 있을 수 있기에 데이터의 차원을 줄이거나 의미있는 정보만 추출
      1. 데이터 분할 : 데이터를 학습, 검증, 테스트 셋으로 나누어 평가

데이터 클랜징

1-1.결측치 처리

I. 결측치

  • missing value로 값이 없는것이라는 뜻이지만 사용하는 언어마다 여러가지로 표현
    • NA - Not Available (유효하지 않은)
    • NaN - Not a Number (숫자가 아닌)
    • NULL - 아무것도 존재하지 않음을 의미

II. 결측치 여부

  • 전체 데이터 건수에서 각 컬럼별 값이 있는 데이터 수를 빼주면 컬럼별 결측치의 개수를 알 수 있다
import pandas as pd
# 결측치 여부 확인
df.isna()          
df.isnull()
len(df) - df.count()

#데이터 프레임의에서 결측치가 있는지 확인
dataframe_name.isnull().any(axis=0)   #기본값은 0(열), axis는 행 
# 위의 코드는 결측치가 있을경우 TRUE로 반환이 된다

#데이터프레임으로 출력
##열 출력
trade.loc[:, trade.columns[trade.isnull().any()]]
#행으로 바꾸려면 
dataframe_name[dataframe_name.isnull().any(axis=1)]

III. 데이터 프레임 결측치 삭제

#1 dropna
dataframe_name.dropna(axis = '' (default 0, #제거할 대상을 지정 0은 행)
                      how ='' (default any), #행또는 열중 어느 부분을 제거할지 지정 any는 결측값이 하나라도 있으면 제거 all은 모든 값이 결측값일시 제거
                      thresh =''  #결측값이 아닌 값의 개수가 이 값보다 작은 행 또는 열을 제거
                      subset ='column_name'  # 특정부분 지정
                      inplace ='' #  True인 경우, 데이터프레임이나 시리즈 자체에서 결측값이 제거된 상태로 갱신.
                      
)
                      
#2 notna
df_cleaned = df[df['column_name'].notna()]  # 열의 na가 없는 행만 추출                     
notna_selected = df[df['column'].notna()]

IV. 결측치 보완

수치형 데이터
  • 특정값 지정
  • 평균,중앙값으로 대체
  • 다른 예측값으로 대체 (ex 머신러닝)
  • 시계열의 경우는 앞뒤 데이터를 통해 결측치 대체 가능 (보간)
    • 시계열 데이터는 일정한 시간 간격으로 측정된 데이터의 순서적인 나열
## 1. 원하는 값으로 대체  fillna 
df_cleaned = df.fillna(value) #value 값으로 대체

## 2. 평균 값으로 대체
mean_value = df['column_name'].mean()
df['column_name'].fillna(mean_value, inplace=True

## 3. 선형 보간
df['column_name'].interpolate(method='linear', inplace=True)

1-2. 중복 데이터 처리

  • 데이터를 수집하다보면 중복된 데이터가 발생할 수도 있다.
  • 중복 확인 및 제거
dataframe_name.duplicated() # 데이터프레임에서 중복된 내용을 bool값으로 반환
dataframe_name[dataframe_name.duplicated()]  #행 출력
datafrmae_name.drop_duplicates(subset ='column_name'  # 중복 여부를 확인할 열 또는 열 리스트 반환되는 것은 시리즈
                               keep ='first/last/false'    # 어떤 행을 유지할지 선택 false는 다 지움 
                               inplace=True)  #데이터프레임 내에서 변경을 수행할지 여부를 설정

1-3. 이상치 처리

  • 이상치는 대두분 값의 범위에서 벗어나 극단적으로 크거나 작은 값
  • 데이터 분석결과를 왜곡하거나 모델 성능을 저하시킬 수 있다.
  • 이상치 찾는 방법
    • 시각화를 통한 탐색 : box plot, scatter plot등을 활용한 시각화를 통해서 분포등을 확인하고 이상치 식별
    • 통계적 방법 : 데이터의 분포나 통계적 특성을 활용해 이상치 찾을 수 있음.
      • (평균, 표준편차를 확인하는 z-score를 계산 하고 특정 임계값 넘는 데이터 포인트를 이상치로 간주)
    • 기계학습 모델 : 클러스터링, 회귀분석, 이상치 탐지 알고리즘 등
    • 도메인 지식 활용
    • 외부 데이터 검증

I. z-score

  • z-score는 통계에서 특정 데이터 포인트가 평균에서 얼마나 떨어져 있는지를 표준편차로 나타내는값
  • z= x−μ/σ (x는 개별 데이터의 포인트값, μ는 전체 데이터의 평균, σ는 전체 데이터의 표준편차)
  • 이 값을 통해서 데이터 포인트의 상대적 위치를 알수 있다. 일반적으로 z-score가 일정한 임계값을 초과하면 해당 데이터 포인트를 이상치로 간주
  • 이상치는 주로 z 값이 특정 임계값 (일반적으로 2 또는 3)을 초과하는 경우로 정의
### 이상치 데이터 인덱스 반환
def outlier(df, col, z):
    return df[abs(df[col] - np.mean(df[col]))/np.std(df[col])>z].index
#위 코드는 인덱스를 반환하기 때문에 출력을 할때 dataframe_name.loc[outlier()]로 출력


#### 이상치 반환
# z-score 계산
z_scores = np.abs((df['Value'] - df['Value'].mean()) / df['Value'].std())
print(z_scores)
# 임계값 설정
threshold = 2

# z-score가 임계값을 넘는 데이터 포인트는 이상치로 간주
outliers = df[z_scores > threshold]

print("Detected outliers:")
print(outliers)
##위 코드에서 z_score는 df에서 이상치를 반환한 시리즈이고 인덱스가 df의 인덱스와 같기 때문에 밑에서 매칭이된다.
  • 위의 코드처럼 표준편차와 평균으로 계산하기에 위의 z-score는 견고하지 않다. 위 방식대로 계산하면 평균과 표준편차는 이상치에 영향을 받기때문이다. 또한 작은 데이터 셋에서는 동작이 하지 않을 수 도있다.
import numpy as np

def outliers_modified_z_score(ys):
    threshold = 3.5

    median_y = np.median(ys)
    median_absolute_deviation_y = np.median([np.abs(y - median_y) for y in ys])
    modified_z_scores = [0.6745 * (y - median_y) / median_absolute_deviation_y
                         for y in ys]
    return np.where(np.abs(modified_z_scores) > threshold)
  • 이방법은 데이터 셋의 중앙 값을 가지고 오는것이다.

II. IQR method

  • 이상치를 찾기 위한 일반적인 방법 중 하나
  • IQR은 데이터의 중간(50%)의 범위를 측정하며, 이 범위에서 벗어나느 값들을 이상치로 간주
  • 동작 원리
    • 데이터를 정렬 -> 데이터의 25번째 백분위수(Q1)과 75번째 백분위수(Q3)를 계산 -> IQR계산(Q3-Q1) -> 이상치의 경계값 계산(이상치는 Q1 - 1.5 IQR 보다 작거나, Q3 + 1.5 IQR 보다 큰 값값.)
#기본
import numpy
q3, q1 = np.percentile(data, [75 ,25])
iqr = q3 - q1

out_data = data[(q1-iqr*1.5< data)|(data>q3 + 1.5 * iqr)]
out_data

###데이터 프레임, 열을 받아 처리
def outlier2(df, col):
    
    q1,q3  = np.percentile(df[col],[25,75])
    iqr = q3-q1
    out_data = df[(q1-iqr*0.5>df[col])|(q3+iqr*0.5<df[col])]
    return out_data

1-4. 구간화(binning / Discretization)

  • 구간화는 연속적인 값을 일정한 구간으로 나누어 범주화하는 작업
  • 연속적인 데이터는 분석이나 모델링 과정에서 처리가 복잡할 수 있다.
  • 변수변환, 이상치 감지, 통계 분석, 모델 성능 향상을 위해 사용\
  • 구간화 종류
    • 등간격 구간화, 등빈도 구간화, 사전지정 구간화
# 등간격 구간화 : 전체 데이터를 일정한 구간으로 나눈다
df['height_bins_equal_width'] = pd.cut(df['height'], bins=3)

# 등빈도 구간화 : 데이터 포인트를 구간 수에 따라 일정한 개수로 넣도록 한다
df['height_bins_equal_freq'] = pd.qcut(df['height'], q=3)

# 사전 지정 구간화 : 설정해둔 구간으로 나눈다
data = {'scores': [85, 92, 78, 95, 88, 60, 73, 85, 90, 82]}
df = pd.DataFrame(data)
bins = [0, 70, 80, 90, 100]
labels = ['D', 'C', 'B', 'A']
df['grade'] = pd.cut(df['scores'], bins=bins, labels=labels)
위에 bins는 간격이므로 label보다 1개 많다.

2. 데이터 변환

  • 원본 데이터를 모델링이나 분석에 적합한 형태로 변경하는 과정
  • 특성을 조작하거나 변형해 성능 개선
  • 방법
    • 데이터 인코딩
    • 텍스트 벡터화
    • 토큰화
    • 차원 축소
    • 날짜 및 시간 처리
    • 파생 특성 생성

2-1. 데이터 인코딩

  • 컴퓨터가 이해할수 있는 형태로 데이터를 변환하는 작업
  • 텍스트나 범주형 데이터를 숫자의 형태로 변환
  • 범주형 데이터 처리, 모델 입력을 위해 사용
  • 방식 : 원핫 인코딩, 라벨 인코딩, 임베딩

I 원핫 인코딩

  • 원핫 인코딩이란 범주형 데이터의 각 범주를 이진 벡터로 변환하는 방법.
  • 각 범주를 별도의 열로 만들어 0과 1로 표현
  • 모델, 알고리즘에 범주형 데이터를 입력하기 위하여 사용
##기본
data = {'색깔': ['빨강', '파랑', '녹색', '빨강']}
df = pd.DataFrame(data)
# 원핫 인코딩 수행
df_encoded = pd.get_dummies(df, columns=['색깔'])
>   색깔_녹색  색깔_빨강  색깔_파랑
 0       0      1      0
 1       0      0      1
 2       1      0      0
 3       0      1      0
## 각 색깔을 나타내는 열로 변화하고, 0 과 1로 표현

II 라벨 인코딩

  • 범주형 데이터를 숫자로 변환하는 인코딩 방법
  • 각 범주에 고유한 숫자를 부여해 데이터 변환
  • 대소 관계가 부여될수 있으며, 순서가 있는 범주형 데이터에 주로 사용
from sklearn.preprocessing import LabelEncoder

# 범주형 데이터
weather = ["맑음", "흐림", "비", "맑음", "흐림", "비"]

# LabelEncoder 객체 생성
label_encoder = LabelEncoder()

# 라벨 인코딩 적용
encoded_weather = label_encoder.fit_transform(weather)

print("Original Weather Data:", weather)
print("Encoded Weather Data:", encoded_weather)

III 임베딩

  • 단어, 문서, 범주 등의 텍스트나 범주형 데이터를 고차원의 벡터 공간에 매핑 하는 방법
  • 사전에 정의된 값이 아니라 모델이 데이터로부터 학습하는데 이를 통해 데이터의 특징을 추출하고 모델의 성능을 향상 가능
  • 차원이 감소하며, 의미정보 포착, 유사도 계산, 일반화 능력 강화등의 장점이 있다.
from gensim.models import Word2Vec
from nltk.tokenize import word_tokenize

# 예시 텍스트 데이터
corpus = [
    "I love natural language processing.",
    "Word embeddings are important for NLP.",
    "Machine learning is fascinating.",
    "NLP deals with text data."
]

# 텍스트 데이터 토큰화
tokenized_corpus = [word_tokenize(sentence.lower()) for sentence in corpus]

# Word2Vec 모델 학습
model = Word2Vec(sentences=tokenized_corpus, vector_size=100, window=5, min_count=1, sg=0)

# 단어 벡터 출력
print("Vector for 'natural':", model.wv['natural'])
print("Vector for 'processing':", model.wv['processing'])
print("Vector for 'machine':", model.wv['machine'])

2-2. 토큰화

  • 텍스트 데이터를 작은 단위로 나누는 작업
  • 문장을 단어나 형태소 등으로 분리한다
###간단하게 라이브러리를 사용할 수 있지만 일반 코드. 열값에 중복된 단어가 많이 들어간다면 제거도 할수 있다.
import re     # 정규식을 표현하기 위한 정규식

def tokenize(name):
    tokens = []
    name_split = name.split(" ")   #split로 name의 인자들을 공백 간격으로 자른다 반환되는 값들은 리스트

    for part_name in name_split: 
        a = re.findall('[A-Z][a-z]*', part_name)   #반환되는 값들은 리스트
        tokens.extend(a)
       
    return tokens
all_tokens = list(df_name["col_name"].apply(tokenize).values)  #배열 값들을 리스트로반환
token_set = []

for token in all_tokens:
    token_set.extend(set(token))

2-3. 스케일링

  • 데이터의 범위를 조절하여 모든 특성이 비슷한 범위 내에서 값을 가지도록 변환하는 데이터 전처리 기법
  • 스케일링 종류
    • 정규화
    • Standatdization( 표준화)

i). Standatdization (표준화)

  • 데이터의 평균이 0이고 표준편차가 1인 분포로 변환하는 정규화 방법 중 하나
  • Z-score 정규화라고도 한다.
  • 표준은 1이고 평균이 0으로 하여 데이터의 분포를 조절하는 목적으로 사용
  • 선형 회귀, 로지스틱 회귀, 서포트 벡터 머신 등의 모델에 활용
  • 데이터가 가우시안 분포를 따를 경우 유용합니다.
    • 가우시안 분포 : 통계학의 확률분포 중 하나로 자연 현상에서 나타내는 데이터의 분포를 모델링하는데 사용
  • 과정
    • 각 데이터의 평균과 표준편차 계산 -> 각 데이터 포인트에서 해당 특성의 평균 뺸다 -> 결과를 표준편차로 나눔
    • 수식으로는 x(new) = x−μ/σ
      • x(new)는 표준화된 새로운 값, x는 원래 데이터 값, μ는 해당 특성의 평균, σ는 해당 특성의 표준편차
기본
x_standardization = (x-x.mean())/x.std()
x_standardization
## 해당 데이터의 모든 값들이 수치일때는 가능하지만 아닐때에는 col을 지정해줘야됨
cols = ['col_name', 'col_name1', 'col_name2', 'col_name3']
df_name1 = (df_name[cols]-df_name[cols].mean())/df_name[cols].std()

ii). Min-Max 정규화

  • 데이터 값을 일정 범위로 변환하여 스케일을 조정하는 데이터 전처리 기법
  • 특정 범위로 데이터를 매핑해 모든 값들이 그 범위 내에 들도록 만든다.
  • 일반 적으로 0과 1사이 값으로 변환 시킨다
  • 이상치에 민감
  • 정규화 수식
    • X(norm) = X-x.min/X.max−X.min
      • X norm는 정규화된 값
        X는 원본 값
        x.min은 원본 값 중 최솟값
        X.max 은 원본 값 중 최댓값
##기본
x_min_max = (x-x.min())/(x.max()-x.min())

## 해당 데이터의 모든 값들이 수치일때는 가능하지만 아닐때에는 col을 지정해줘야됨
cols = ['col_name', 'col_name1', 'col_name2', 'col_name3']
df[cols] = (df[cols]-df[cols].min())/(df[cols].max()-df[cols].min())
trade.head()

iii). Maxabs 정규화(MaxAbsScoler)

  • 각 특성의 절대값이 0과 1사이가 되도록 스케일링 -> 모든값은 -1과 1사이
  • 데이터가 양수일 경우에는 minmax 정규화와 같다
  • 이상치에 민감
  • 공식
    • x_max_abs = x / max_abs_value
import numpy as np
def max_abs(data):
	max_abs = np.max(np.abs(data),axis = 0 )
	scaled_data = data / max_abs_values
    return scaled_data
  • 추가로 scikit-learn의 standardscaler,minmaxscaler을 사용할수도 있음

profile
전공자 학생

0개의 댓글