맞춤형 플랫폼 개발 도전기 (웹개발, 딥러닝, 블록체인)

빅데이터분석기사 실기 Basic 1 (작업형 : Numpy, Pandas, EDA, Cleansing) 본문

빅데이터분석기사

빅데이터분석기사 실기 Basic 1 (작업형 : Numpy, Pandas, EDA, Cleansing)

경이가 꿈꾸는 플랫폼 개발 2021. 11. 11. 20:48

빅데이터분석 능력을 평가하는 자격증 중, 국가기술자격증은 없었다.

하지만 작년에 빅데이터분석기사라는 시험이 시행됨에 다라 빅데이터분석 능력을 일부라도 검증받을 수 있게 되었다. 

하지만 절대적인 척도가 될 수는 없다. 빅데이터분석이라는 분야가 정말 넓고, 깊은 전문성을 요하기 때문이다. 그래서 정보처리기사처럼 '기본'을 갖췄는지에 대한 평가 정도라고 생각하면 될 것 같다.

 

12월 4일 빅데이터분석기사 시험이라, 오늘부터 짬을 내서 공부를 해보려 한다. 나 외에도 준비하는 사람이 있다면 도움을 받았으면 좋겠다는 생각으로 기록을 남긴다.

※ 자동완성이 없기 때문에 함수, 패키지의 이름을 제대로 기억해야 한다.

 

아래에 빅데이터분석기사에서 꼭 알아야 하는 Numpy, Pandas의 기본적인 부분들을 대략적으로 정리해 놓았다.

Numpy와 Pandas에 대한 자세한 내용이 궁금하다면 아래 페이지에서 찾아서 보면 좋을 것 같다.

 

'딥러닝·머신러닝' 카테고리의 글 목록

장교에서 개발자로. 생각하는대로 살지 않으면, 사는대로 생각하게 된다.

katieyoon-the-developer.tistory.com

 

 

 

1. Numpy

 

Nunmpy는 기본적으로 과학 계산을 위한 Python 분석 패키지이다. 다차원 배열을 처리하는데 특히 유용하다.

import numpy as np 로 불러오고, 연산 함수들은 np.(연산함수) 형식으로 사용한다.

 

기본적인 연산 함수로는 abs, sqrt(제곱근), square(제곱), exp(지수계산), Log(지수계산), add(배열 합), subtract(배열 차), multiply(배열 곱), amax, amin 등이 있다. 그냥 min을 쓸 때에는 변수명.min() 형태로 사용한다.

 

Numpy에서 일정 규칙 없이 내가 지정한 원소로 구성된 배열을 생성하는 방식에는 np.array(배열)해서 만드는 방식이 있고, 규칙성이 있는 배열을 만드는 방식에는 np.arange(start, end, step) 혹은 np.arange(number) 형태로 사용한다.

부가적인 옵션에는 dtype=데이터타입 으로 데이터타입을 지정할 수 있다.

reshape 같은 경우는 기본적으로 1xN 의 배열로 생성된 array를 NxM의 배열로 재정렬(?) 해주는 함수이다. 그리고 행 우선으로 할당하는지, 열 우선으로 할당하는지에 따라 order='F'(열 우선)라는 옵션이 있고, default는 행 우선이다.

arr1 = np.arange(1,12,2, dtype=int)
arr1 = arr1.reshape(2,3)
print(arr1)
arr2 = arr1.reshape(2,3, order='F')
print(arr2)

arr3 = np.arange(10)
print(arr3)

# [[ 1  3  5]
#  [ 7  9 11]]

# [[ 1  5  9]
# [ 3  7 11]]

# [0 1 2 3 4 5 6 7 8 9]

 

 

 

2. Pandas

 

자료구조 및 데이터분석, 처리를 위해 필요한 가장 핵심적인 패키지이다.

쉽게 분류하면 Numpy는 계산, Pandas는 시각화 라고 분리해서 생각하면 편하다.

Pandas의 자료구조에는 크게 Series와 DataFrame이 있다. 각각의 내용이 길어 자세한 설명은 아래 페이지에서 확인할 수 있다.

 

Python Pandas Basic 1 (Series)

pandas의 기본 객체 중 하나로, numpy의 ndarray를 기반으로 인덱싱 기능이 추가된 1차원 배열을 나타낸다. value index 의 형태로 작성이 되어 있고 index를 지정하지 않을 시, 기본적으로 ndarray와 같이 0-

katieyoon-the-developer.tistory.com

 

Python Pandas Basic2 (DataFrame)

Series가 1차원이라면 DataFrame은 2차원으로 확대된 것이라고 생각하면 쉽다. DataFrame은 2차원이기 때문에 인덱스가 row, column로 구성되어 있다. (row는 개별 데이터, column은 개별 속성) DataFrame은 데이..

katieyoon-the-developer.tistory.com

설명이 길다고 했지만 한 문장으로 줄이면 Series는 1차원, DataFrame은 2차원이라고 생각한다면 접근하기 쉽겠다.

 

★중요

DataFrame을 대부분 쓰게 될텐데, DataFrame에서 열(column)에 접근하는 방식에는

1. DataFrame[['행이름']] ← [ ] 하나만 사용하면 Series가 된다. 

2. DataFrame[DataFrame.column명[[행 번호]]]

3. DataFrame.loc[ 행시작 : 행끝 , 열시작 : 열끝 ] ← 특정 열이라면 : 없애고 이름으로 접근하면 된다.

4. 위와 같이 이름으로 접근할 게 아니라면 DataFrame.iloc[ 행시작 : 행끝 , 열시작 : 열끝 ] ← 0부터 시작해 몇 번째 행이고 열인지 파악해서 찾는 방법도 있다.

 

행 접근법은 간단하다. DataFrame.head(num)로 상위 num개의 데이터를 불러오거나 DataFrame.tail(num) 으로 하위 num개의 데이터를 가져올 수 있다. DataFrame[ : ] 를 사용해서 특정 행들을 가져올 수도 있다. 특정 조건으로 찾고 싶다면 위에 DataFrame[DataFrame.column명[[행 번호]]] 에서 조금만 변화를 줘서 DataFrame[DataFrame['열이름']==값] 이런 식으로 찾을 수도 있다. 간단한 예로 아래처럼 구할 수 있다. (많이 쓰기 때문에 직접 눈으로 보는게 좋다,)

titanic_df[titanic_df['Survived']==1]

 

 

3. EDA(Exploratory Data Analysis) , Data Cleansing

 

Numpy와 Pandas의 사용이 자유자재로 가능해지면 탐색적 데이터 분석과 데이터 정제도 가능하다.

순서라고 하긴 좀 그렇지만, 탐색적 데이터분석(EDA)를 하기 위해서는 봐야 하는 것들이 있다.

 

 

1. DataFrame.head() → 자료의 전체적인 모습을 확인 

                               데이터가 범주형인지 수치형인지 확인한다.

   DataFrame.shape() → 몇개의 행과 열로 이루어져 있는지 확인

   DataFrame.info() → NaN 값이 있는지 확인

 

 

 

2. 범주형 변수 : DataFrame['열이름'].value_counts() 해서 범주별 빈도를 파악한다.

   수치형 변수 : DataFrame.describe() → 기술통계량 확인하면서 대략적으로 이상치가 있는지 눈으로 확인한다.

                     DataFrame.skew()를 통해서 왜도 확인 → 0일 경우 정규분포 일치

                                                                          |왜도| > 2 면 한족으로 치우쳐져 있다는 뜻

                                                                          양수일 경우 왼쪽에 치우침, 음수일 경우 오른쪽 치우침

                     DataFrame.kurtosis()를 통해 첨도 확인 → 0일 경우 정규분포의 높이와 일치

                                                                           값이 클수록 중간에 몰려 있음

 

2-1. 수치형 변수일 때에서는 여러가지 함수를 사용해야 할 경우가 많다. (편의상 ( )는 생략하겠다)

      직관적으로 어떤 함수인지 보이는 것을 제외하고 설명을 붙였다.

      count

      describe

      min, max,

      argmin, argmax : 최소, 최대값을 갖고 있는 색인 위치 반환

      idxmin, idxmax : 최소, 최대값을 가지고 있는 색인의 값 반환

                            → set_index 처럼 내가 index를 지정했을 경우에는 index에 값이 있을 수 있다. 

      quantile : 0부터 1까지의 분위수로, DataFrame['열이름'].quantile(q = 0.25) 이런식으로 분위를 줄 수 있다.

      sum

      mean

      median

      mad : 평균값에서 절대 평균편차

      var : 표본 분산

      std :  표본 정규분산

      skew : 왜도

      kurt : 첨도

      cumsum, cummin, cummax, cumprod : 누적합, 누적 최소값, 누적 최댓값, 누적곱

      diff : 1차 산술차, 뒤 index와의 값 차이 +, - 구분한다. (시계열 데이터 사용시 용이하다)

      pct_change : 퍼센트 변화율 계산 (diff를 %로 바꿨다고 생각하면 됨)

      corr : DataFrame의 모든 변수간 상관관계 계산해서 반환

      cov : DataFrame의 모든 변수간 공분산 계산해서 반환

 

 

 

 

3. 필요시 Column 명 변경 (값 변경은 나중에)

DataFrame['열이름'].replace(['열이름1', '열이름2', '열이름3', '열이름4'], ['새이름1', '새이름2', '새이름3', '새이름4'])

 

 

 

 

4. 이상치와 결측치 처리

위의 과정들을 완료하면, 대략적으로 NaN 값은 어느 Column 에 얼마나 있는지, 이상치가 있는지 없는지 파악이 된다. 그렇다면 이제 이 값들을 없애거나, 채워줘야 한다.

 

 

 

4-1. 이상치 처리

이상치는 보통 1사분위수+(1.5xIQR) 과 3사분위수-(1.5xIQR) 사이에 들어가있지 않은 값을 이상치라고 한다.

그래서 IQR을 구하고 그 범위에 없는 값을 없애거나, 다른 값으로 대체하는 방법이 있다.

Q1 = df['creatinine_phosphokinase'].quantile(q=0.25)
Q3 = df['creatinine_phosphokinase'].quantile(q=0.75)
IQR = Q3 - Q1
df[(df['creatinine_phosphokinase']<(Q3+1.5*IQR)) & (df['creatinine_phosphokinase']>(Q1-1.5*IQR))].iloc[:,:11]

이렇게 이상치가 빠진 모습을 볼 수 있다. 데이터가 너무 많아서 11번째 열까지 보이게 자른 것이고, 299행에서 270개 행으로 이상치 29개가 빠진 모습을 볼 수 있다.

변화 전과 후의 히스토그램을 그렸을 때, 이상치가 많이 줄어든 것을 볼 수 있다. 이런 식으로 이상치를 제거하는 방법이 있다.

 

 

 

4-2. 변수 변환

변수 변환은 값이 한쪽으로 쏠려 있다 싶을 때 활용하는 변환이다. 특히, 단위가 너무 커서 왜곡이 있을 수 있다고 생각이 들 때 활용한다.

np.log() (로그 변환) 과 np.sqrt() (제곱근 변환)이 대표적이다. 활용을 많이 하지는 않는 것 같지만, 짚고 넘어가자면, 왜도가 심할 때 활용할 수 있다. 위 예가 마침 왜도가 4.463110084653752로 2를 넘는 수치기 때문에 변수 변환을 한번 해보겠다.

np.log(df['creatinine_phosphokinase']).skew()
np.log(df['creatinine_phosphokinase']).hist()

# 0.41400698865657504

np.sqrt(np.sqrt(df['creatinine_phosphokinase'])).skew()
np.sqrt(np.sqrt(df['creatinine_phosphokinase'])).hist()

# 1.1466190774815572

결과적으로, 각각 이렇게 왜도가 줄어든 모습을 확인할 수 있다.  np.sqrt 보다는 np.log가 효율이 좋은 경우가 (경험상) 많았고, 이런 식으로 단위가 주는 영향을 없앨 수도 있다. 변수가 2개(x, y)라면 correlation을 찾는 것에 효율적일 가능성이 높다.

 

4-3. 결측치 처리

앞에서 isnull().sum()을 통해 각 변수별로 결측치가 얼마나 있는지 확인은 했을 것이다.

확인한 결측치를 처리할 때는 .dropna() 혹은 .fillna()를 활용할 수 있다. 여기서 중요한 점은 axis이다. drop할 게 너무 많아서 별로 의미 없는 변수라고 느껴진다면 df[['변수명']].dropna(axis=1) 이런 식으로 변수 자체를 없앨 수도 있고, 적다면, df[['변수명']].dropna()는 기본값이 axis=0 이기 때문에 별다른 옵션 없이 .dropna()하면 된다.

dropna()는 DaraFrame을 대상으로 한다 따라서 반드시 []가 두 개 여야 한다 (안 그러면 Series)

단, axis=1해서 열 자체를 제거해버리면 null이 있는 모든 열이 다 삭제되어 버려서, 정말 필수적인 데이터를 잃을 수도 있다. 때문에 나는 열을 삭제할 때는 dropna() 말고 DataFrame.drop( ['열1', '열2'], axis=1) 또는 DataFrame.pop('열이름'), del DataFrame['열이름'] 등을 사용해서 NaN값을 지우는 편이다.

df.drop( ['GNPOld'], axis=1)
df.pop('GNPOld')
del df['GNPOld']

이렇게 GNPOld 라는 열이 삭제된 것을 알 수 있다.

하지만, 데이터를 삭제하는 것보다는 (거의 대부분의 경우에는) 데이터를 특정값으로 대체하는게 낫다. 방법은 fillna()를 사용한다. 아래는 fillna()를 사용한 예시이다.

fillna()는 보통 어떤 한 값으로 대체할 때 사용한다. 가장 위는 원본, 아래는 대체된 결과이다.

df['GNPOld'].fillna(df['GNPOld'].mean(), inplace=True)

fillna(함수) 형태로 함수가 들어갈 수도 있다.

def fill_GNP():
    return df['GNPOld'].mean()

df['GNPOld'].fillna(fill_GNP(), inplace=True)

apply(함수)를 활용해서 할 수도 있다. 특히 Pclass가 1이면 'C23 C25 C27'을 넣어라 이런 식으로 어딘가를 그룹화하고, 그 그룹에 해당하는 값을 NaN 값에 넣고자 할때 많이 활용한다.

바로 아래는 원본이다. apply()로 함수를 적용해서 Pclass에 해당하는 값에 따라 다르게 Cabin의 NaN에 값을 채웠다. 

fill_cabin = {1 : 'C23 C25 C27', 2:'G6', 3 : 'F2'}
fill_cabin_func = lambda x : x.fillna(fill_cabin[x.name])
df.groupby('Pclass').apply(fill_cabin_func)

적당한 예시가 없어서 제일 만만한 titanic.csv를 가져와서 해보았다. 머신러닝 프로세스에 들어가기 전에 기본적으로 알고 있어야 하는 개념은 이 정도로 하겠다.

이제 본격적으로 데이터분석기사 실기시험 작업형에 필요한 머신러닝 프로세스에 대한 설명을 하려한다.

※ 필답형은 꾸준히 문제를 만들어 올릴 생각이다.

 

 

 

 

데이터 출처는 Kaggle의 Student's Academic Performance 데이터이다.

 

Students' Academic Performance Dataset

xAPI-Educational Mining Dataset

www.kaggle.com

 

 

Comments