파이썬 머신러닝 판다스 데이터 분석 5강 복습

 

1. 누락 데이터 처리

머신러닝 등 데이터 분석의 정확도는 분석 데이터 품질에 의해 좌우

>> 누락 데이터, 중복 데이터 등 오류 수정하고, 분석 목적에 맞게 변형해야 함

 

 

# 누락 데이터 확인

import seaborn as sns

df = sns.load_dataset('titanic')
df.head()

>> seabron 라이브러리를 불러오고

    'titanic' 데이터 셋 가져오기

 

 

# deck 열 Nan개수 계산하기

nan_deck = df['deck'].value_counts(dropna=False)
print(nan_deck)
## NaN  688 >> dirty

>> value_counts() 메소드를 이용하여 'deck' 열에 688개의 데이터가 있는 것을 파악할 수 있음

     이때 default는 dropna=True임

     drop=False 옵션을 사용해야 NaN값까지 출력됨

 

 

# isnull() : 메소드 누락 데이터 찾기
print(df.head().isnull())

# notnull() : null 값이 아닌 데이터 값 찾기
print(df.head().notnull())

- isnull() : 누락 데이터면 True를 반환하고, 유효한 데이터가 존재하면 False 반환

- notnull() : 유효한 데이터가 존재하면 True를 반환하고, 누락 데이터면 False 반환

 

df.isnull().sum(axis=0)

 

>> isnull().sum(axis=0) 메소드를 이용해 참(1)의 합을 구함

     각 열의 누락 데이터(NaN) 개수를 구할 수 있음

>> 이런 NaN값을 어떻게 처리할지  고민해야 한다

 

 

 

# 누락 데이터 제거(중요)

# for 반복문 각 열의 NaN 개수 계산하기(묘미****)

null_df = df.isnull()

for col in null_df.columns:
    null_count = null_df[col].value_counts()  # 각 열의 NaN 개수 파악
    
    try:
        print(col, ':', null_count[True])  # NaN 값이 있으면 개수 출력
    except:
        print(col, ':', 0)  # NaN 값이 없으면 0개 출력

>> 각 열(변수)에 누락 데이터가 몇 개 씩 포함되어 있는지 체크

 

 

# NaN 값이 500개 이상 (threshold)인 열 모두 삭제
df_thresh = df.dropna(axis=1, thresh=500)
df_thresh.columns

# deck만 삭제

>> 'deck' 열의 누락 데이터가 매우 많기 때문에 삭제하여 분석에서 제외하는 것이 좋다

     dropna() 메소드에 thresh=500 옵션을 적용 >> NaN 값을 500개 이상 갖는 모든 열 삭제

 

# age 열에 나이 데이터가 없는 모든 행 삭제
df_age = df.dropna(subset=['age'], how='any',axis=0)
len(df_age)

>>'age'열의 행 중에서 NaN 값이 하나라도 존재하면 모든 행(axis=0) 삭제

 

>> how='any' (default) : NaN 값이 하나라도 존재하면 삭제

     how = 'all' : 모든 데이터가 NaN 값일 경우에만 삭제

 

 

 

 

# 누락데이터 치환

 

- 데이터 중에서 일부가 누락되어 있더라도 나머지 데이터를 최대한 살려서 데이터 분석에 활용

 

- 평균(mean) 값으로 치환

mean_age = df['age'].mean(axis=0)
df['age'].fillna(mean_age, inplace=True)

>> 'age' 열에 들어 있는 값들의 평균을 계산하여 mean_age에 저장

     mean() 메소드를 적용하면 NaN 을 제외하고 평균을 계산

 

>> 'age' 열의 NaN 값을 제거하지 않고, 나머지 승객의 평균 나이로 치환

 

>> mean 대신 median을 사용해도 됨.

 

 

 

- 가장 많이 나타나는 값으로 치환

# most_freq(비정형 데이터 : 최대빈도)
most_freq = df['embark_town'].value_counts(dropna=True).idxmax()
df['embark_town'].fillna(most_freq, inplace=True)

# 누락 데이터가 NaN이 아니라 ?로 값으로 입력된 경우
df.replace('?', np.nan, inplace=True)

>> idxmax() 메소드 : 가장 큰 값을 갖는 도시를 찾음

 

>> NaN값을 포함해서 누락 데이터들은 idxmax()에서 찾은 값으로 변경됨 

 

 

 

 

- 이웃하고 있는 값으로 바꾸기

# embark_town 열의 NaN 값을 바로 앞에 있는 828행의 값으로 변경
df['embark_town'].fillna(method='ffill', inplace=True)
df['embark_town'][825:830]

>> method='ffill' 옵션을 추가하면 NaN이 있는 행의 직전 행에 있는 값으로 바꿔줌

     method='bfill' : NaN이 있는 행의 바로 다음 행에 있는 값을 가지고 치환 

 

 


 

2. 중복 데이터 처리(duplicated)

 

- 중복 데이터 확인

# 중복된 데이터 처리(duplicated)

import pandas as pd
df = pd.DataFrame({'c1':['a','a','b','a','b'],
                  'c2':[1,1,1,2,2],
                  'c3':[1,1,2,2,2]})
df

df_dup = df.duplicated()
df_dup

>> duplicated() 메소드 : 동일한 관측값이 중복되는지 여부 확인

                                       전에 나온 행들과 비교하여 중복되는 행이면 True 반환, 처음 나오는 행에 대해서는 False 반환

 

 

- 중복 데이터 제거

# 데이터프레임에서 중복 행 제거
df.drop_duplicates()

# c2, c3열을 기준으로 중복 행 제거
df.drop_duplicates(['c2','c3'])

col_dup = df['c2'].duplicated()

>> drop_duplicates() 메소드 : 중복 데이터 제거

 

 


 

 

 

3. 데이터 표준화

 

- 같은 데이터셋 안에서 서로 다른 측정 단위를 사용한다면, 측정 단위를 동일하게 맞출 필요가 있다.

 

# 참고
https://www.datadata.link/qa03-3-2/
# 변동계수 CV : 변동계수는 표준편차를 산술평균으로 나눈 것
$$CV =   \frac{ \sigma }{ \mu } $$
# 측정단위가 서로 다른 자료를 비교할 때는 더욱 요긴
# 변동계수의 값이 클수록 데이터의 상대적인 값의 차이가 크다

 

 

 

- 단위 환산

# read_csv() 함수로 df 생성

df = pd.read_csv('auto-mpg.csv', header=None)

# 열 이름
df.columns = ['mpg','cylinders','displacement','horsepower','weight',
              'accleration','model_year','origin','name']
print(df.head(3))

 

 

# mpg(mile per gallon)를 kpl(kilometer per liter)로 변환 (mpg_to_kpl = 0.425)
mpg_to_kpl = 1.60934/3.78541

df['kpl'] = df['mpg'] * mpg_to_kpl

df['kpl'] = round(df['kpl'],2)  # df['kpl'].round(2)  소수점 둘째자리까지
df.head(1)

>>  mile/gallon >> km/L

     1마일은 1.770934km, 1갤런은 3.78541리터이므로 1mpg = 0.425 km/L

 

>> df['mpg'] 각 열의 값에 1mpg(=0.425 km/L) 를 곱한 값을 df['kpl'] 에 저장하고 소수점 둘째자리에서 반올림

 

 

 

- 자료형 변환

 

import numpy as np

# ? >> NaN
df['horsepower'].replace('?',np.nan, inplace=True)

# 누락 데이터 있는 행 삭제
df.dropna(subset=['horsepower'], axis=0, inplace=True)  # default : axis=0

# 문자열(object) >> 실수형(float)
df['horsepower'] = df['horsepower'].astype('float')

 

df['origin'].unique()

# 정수형 데이터 >> 문자형 데이터
df['origin'].replace({1:'USA',2:'EU',3: 'KOREA'}, inplace=True)

# 문자열 >> 범주형
df['origin'] = df['origin'].astype('category')

# 범주형 >> 문자열 반환
df['origin'] = df['origin'].astype('str')

 

 


 

 

 

4. 범주형(카테고리) 데이터 처리

 

- 구간 분할

 

데이터 분석 알고리즘에 따라서는 연속 데이터를 그대로 사용하기 보다는 일정한 구간(bin)으로 나눠서 분석하는 것이 효율적

 

연속 변수를 일정한 구간으로 나누고,

각 구간을 범주형 이산 변수로 변환하는 과정을 구간 분할 (binning)

>> cut() 함수 이용

 

# 구간분할
# np.histogram 함수로 3개의 bin으로 나누는 경계 값의 리스트 구하기

np.histogram(df['horsepower'], bins=3)

count, bin_dividers = np.histogram(df['horsepower'], bins=3)
bin_dividers

# 46~107.3, 107.3~168.6, 186.6~230 >> 3개의 구간

>> bin_dividers

>> 46~107.3 구간, 107.3~168.6 구간, 168.6~230 구간

 

# 3개의 bin에 이름을 지어 줘야지
bin_names = ['저출력','보통 출력','고출력']

# pd.cut 함수로 각 데이터를 3개의 bin에 할당
df['hp_bin'] = pd.cut(x=df['horsepower'],
               bins = bin_dividers,
               labels = bin_names,
               include_lowest=True)
               
df[['horsepower','hp_bin']].head(10)

>> cut() 함수 옵션 설정

     앞에서 구한 경계값의 리스트(bin_dividers)를 bins 옵션에 할당하고 각 구간의 이름(bin_names)을 labels옵션에 할당

 

>> include_lower = True : 각 구간의 낮은 경계값을 포함

 

 

 

- 더미 변수

 

범주형 데이터를 회귀분석 등 머신러닝 알고리즘에 바로 사용할 수 없는 경우가 있음 

>> 컴퓨터가 인식 가능한 입력값으로 변환해야 함

 

이럴 때 숫자 0 또는 1로 표현되는 더미 변수(dummy variable) 사용

(해당 특성이 존재하면 1, 존재하지 않으면 0)

>> 원핫인코딩(one-hot-encoding)이라고 부름

>> get_dummies() 함수 사용

 

# 더미 변수

hp_dummy = pd.get_dummies(df['hp_bin'])

>> pd.get_dummies() 함수를 이용해서 범주형 변수의 모든 고유값을 각각 새로운 더미 변수로 변환

 

 

# one-hot encoding

# sklearn 라이브러리 불러오기
from sklearn import preprocessing

# label_encoder 객체 만들기
le = preprocessing.LabelEncoder()
oh = preprocessing.OneHotEncoder()

# label encoder로 문자열 범주 >> 숫자형 범주로 변환(0,1,2)
onehot_le = le.fit_transform(df['hp_bin']) 

# (1차원 벡터 >> ) 2차원 행렬 구조 변환
onehot_le_matrix = onehot_le.reshape(len(onehot_le),1)

# 희소행렬(sparse matrix)
oh.fit_transform(onehot_le_matrix)
type(oh.fit_transform(onehot_le_matrix))

# 희소행렬 : 행렬 안의 많은 항들이 0으로 되어있는 행렬 >> (행,열) 좌표와 값 형태로 정리

>> (0,1) 0행 1열 위치에 데이터 값 1 

 

>> 선형대수학에서 정의하는 희소행렬(sparse matrix)

     1차원 벡터 >> 2차원 행렬 >> 희소행렬

 

>> 희소행렬은 (행, 열) 좌표와 값 형태로 정리됨

 

 

 


 

 

 

5. 정규화

 

- 숫자 데이터의 상대적인 크기 차이 떄문에 머신러닝 분석 결과가 달라질 수 있음

>> 상대적인 크기 차이를 제거할 필요가 있음

 

- 각 열(변수)에 속하는 데이터 값을 동일한 크기 기준으로 나눈 비율로 나타내는 것 : 정규화

정규화를 거친 데이터의 범위 0~1 또는 -1~1

 

df.describe()

>> 요약통계 정보로 최대값(max) 확인

 

 

- 정규화

# horsepower 열의 최댓값을 절댓값으로 모든 데이터를 나눠서 저장

df.horsepower_temp = df.horsepower / abs(df.horsepower.max())
df.horsepower_temp[:5]

 >> 각 열(변수)의 데이터를 해당 열의 최댓값(의 절댓값)으로 나누는 방법

     어떤 열의 원소 값을 그 열의 최댓값으로 나누면 가장 큰 값은 최댓값 자기자신을 나눈 1

 

 

# min-max scailing (범주 : 0 ~ 1)

# horsepower 열의 통계 요약정보 >> 최대값(max), 최소값(min) 확인 
df.horsepower.describe()
# min       46,  max      230


# (x - x.min) / (x.max - x.min)

min_x = df['horsepower'] - df['horsepower'].min()
min_max = df['horsepower'].max() - df['horsepower'].min()

df.horsepower_minmax =  min_x / min_max

df.horsepower_minmax.describe()

>> 각 열(변수)의 데이터 중에서 최댓값(max)과 최솟값(min)을 뺀 값으로 나누는 방법

     (각 열 데이터 - 해당 열 최솟값) / (해당 열의 최댓값 - 해당 열의 최솟값)

     최소 0부터 최대 1사이의 범위로 변환

복사했습니다!