본문 바로가기

데이터 전처리/python

파이썬 범주화,결측치 처리기법

 

결측치 처리기법

A = {
    'subject' : ["미적분학","선형대수학","해석학","정수론","수리통계학","수학을 위한 프로그래밍"],
    '평점' : [3.8,4.5,4.1,3.2,4.7,5],
    '학점' : [3,3,3,2,2,2],
}
df=pd.DataFrame(A)

#결측치 처리.
#1.결측치 행을 제거.
#2.결측치를 mean,median등 어떤 함수로 채우는 방법
df['점수'] = [88,97,79,95,94,np.NAN]

#1.결측치 행 제거. df.dropna 사용.
#물론 직접 df를 행,열을 조작하는거라 정말로 제거해주려면 df = df.dropna() 해줘야한다.
df.dropna()

아래는 수치형인 단일 컬(열)을 mean,median으로 결측치 처리해주는 방법입니다.

수치형 결측치를 중심위치값에 해당하는 평균과 중앙값으로 채우는 방법

#2.결측치를 mean,median등 어떤 함수로 채우는 방법
df

df['점수'].fillna(df['점수'].mean())

df['점수'].fillna(df['점수'].median())

다음은 다수의 컬(열)이 결측치를 가졌을 때 처리하는 방법입니다.

컬에 들어간 원소(요소)에 대해 수치형/문자형,범주형 이런식으로 컬을 분류했습니다.

결측치를 평균으로 처리하고 pandas의 concat을 이용해 수치형 컬과 그 외의 컬을 합치는 모습
결측치를 중앙값으로 처리하고 pd.concat이용

#만약 결측치를 가진 col이 많다면?
df['수강금액'] = [200000,280000,280000,np.NAN,320000,180000]
df['수강인원'] = [48,38,np.NAN,17,15,44]
df['좌석수'] = [48,38,25,np.NAN,22,45]

#2.df의 수치형과 문자형(+범주형)을 col 이름으로 분리하라.
num_col = df.select_dtypes(include='number').columns

df.dtypes

char_col =df.select_dtypes(include=['object','category']).columns

#3-1.수치형 데이터의 NAN값을 처리하자. mean으로
df_mean =df[num_col].fillna(df[num_col].mean())

#3-2. 수치형 데이터의 NAN값을 처리하자. median으로
df_median = df[num_col].fillna(df[num_col].median())

#4.pd.concat을 사용하여 mean,median 데이터를 df_mean,df_median으로 따로 출력하라.
df_merged_mean = pd.concat([df[char_col],df_mean],axis=1)
df_merged_mean

df_merged_median = pd.concat([df[char_col],df_median],axis=1)
df_merged_median

다음은 행에 조건을 걸어 추출하는 방식입니다. R에서는 dplyr 패키지를 사용하여 filter와 여기에 열도 골라낼려면 select를 사용하여 하시면 됩니다. 조건이 두개이상인 경우 &같은 연산자를 쓸 때 ()를 꼭 해주세요.

행에 조건을 걸어 하는 방법

#1.
#df_merged_mean로 수강금액이 25만 이하를 추출하라.
#미적분학,프로그래밍이 선정 되어야한다.
df_merged_mean[df_merged_mean['수강금액']<=250000]


#2.
#df_merged_mean로 수강금액이 25만 이상, 수강인원이 30명이상을 추출하라.
df_merged_mean[(df_merged_mean['수강금액']>=250000) & (df_merged_mean['수강인원']>=30)]

 

이제 범주형으로 만드는 방법입니다.

범주형1

#1.
#수강인원 수로 혼잡도를 범주로 나타낼려고한다.
#15명 이하:양호,  16명이상 30명미만 :보통 , 30명이상 40명미만 :혼잡, 40명이상 :매우혼잡으로 분류하라.
def congestion(x1):
    if x1<=15:
        return '양호'
    elif 16< x1 <30:
        return '보통'
    elif 30<=x1<40:
        return '혼잡'
    else:
        return '매우혼잡'
    
    
    df_merged_mean['수강인원'].apply(congestion)

다음은 두 컬(열)을 비교하여 범주화시키는 방법입니다.

잘못된 예시- 오류발생
오류

두개의 컬이 하나로만 보고 x1에만 적용되는 모습이다. 그러면 어떻게 하면 될까?

옳은 방법

#이번엔 x2를 못받는 것을 알았기 때문에, 아예 하나의 스칼라(x)만을 지정했다.
#여기서 인덱싱하는 기법으로 골라냈다.
def error(x):
    if x['수강인원'] > x['좌석수']:
        return 'Impossible'
    else:
        return 'Possible'
        
df_merged_mean['가능여부']=df_merged_mean.apply(error, axis=1)
df_merged_mean

다음은 조건을 두개를 걸어 범주형 데이터를 만드는 방법이다.

두개의 조건을 사용하여 범주형데이터 만들기

#3.
#수강인원 수로 혼잡도를 범주로 나타낼려고한다.
#15명 이하:양호,  16명이상 30명미만 :보통 , 30명이상 40명미만 :혼잡, 40명이상 :매우혼잡으로 분류하라.
#양호하면서,수강인원이 좌석수의 90프로이하면 폐강하기로 했다. 이를 범주화하라.
def course(x):
    if (x['수강인원']<=15) & (x['수강인원']<= x['좌석수']*0.9):
        return "폐강"
    else:
        return "개강"
        
 df_merged_mean['개강폐강여부']=df_merged_mean.apply(course,axis=1)
 df_merged_mean

다음은  데이터프레임에서 특정문자로 추출하는 방법과 결측치를 문자로 처리하는 방법이다.

#1.
#강사진 이름이 브레첼? 브레줼 브레까진 맞는 것같은데.. 'df_merged_mean'에서 이를 추출해보자
df_merged_mean[df_merged_mean['강사진'].str.contains('브레')]

데이터 수가 수천개만 되어도 육안으로 결측치 확인이 어렵다. 그렇기에 먼저 우리가 해야할 일은

결측치가 있는지 확인을 먼저 해줘야 한다. 그리고 그 결측치가 있는 행을 알면 좋겠다.

결측치를 문자로 - 1

 

결측치를 문자로 -2

A = {
    'subject' : ["미적분학","선형대수학","해석학","정수론","수리통계학","수학을 위한 프로그래밍"],
    '평점' : [3.8,4.5,4.1,3.2,4.7,5],
    '학점' : [3,3,3,2,2,2],
    '선수과목' : [np.NAN,'미적분학','선형대수학/미적분학','선형대수학/미적분학','선형대수학/미적분학',np.NAN]
}
df2 = pd.DataFrame(A)
df2

#1.
#먼저 결측치가 있는가?
df2.isnull().sum()

#2.
#선수과목에서 두개 존재한다. 이의 행은 무엇인가?
df2.isnull()

#저 선수과목 True의 행만 찾아내는 것이 목표다. 
#any(axis=1)를 하면 각 행에 True가 하나라도 있으면 True 아니면 False로 출력된다.
df2.isnull().any(axis=1)

df2[df2.isnull().any(axis=1)]

#3.
#선수과목 NAN를 '없음'으로 변환하라.
df2['선수과목'] = df2['선수과목'].fillna('없음')

df2