데이터프레임에서 행별로 이상치 판단하기 (코딩테스트 복기)

1. 예시 데이터 생성

 

import pandas as pd
import numpy as np

a = ['xdjwew1235453kdrew',75,np.nan,np.nan]
b = ['jgierw0548323kgfe',54,36,89]
c = ['hjeir3058372jdkw',23,85,np.nan]
d = ['gjewoe02853klfw',98,94,92]
e = ['guehrwenk29584034kgneiew',np.nan,np.nan,55]

df = pd.DataFrame([a,b,c,d,e])

 

 

여기서 소소한 팁으로 np.nan으로 NaN값을 넣을 수 있다

 

'NaN'이나 nan이나 NaN이나 이런거 안됨

 

 

2. 행의 값들을 가져오는 방법

 

df.values하면 데이터프레임의 행들을 numpy array로 가져온다

 

df.values

array([['xdjwew1235453kdrew', 75.0, nan, nan],
       ['jgierw0548323kgfe', 54.0, 36.0, 89.0],
       ['hjeir3058372jdkw', 23.0, 85.0, nan],
       ['gjewoe02853klfw', 98.0, 94.0, 92.0],
       ['guehrwenk29584034kgneiew', nan, nan, 55.0]], dtype=object)

 

 

3. 이상치 판단하기

 

보통 df.isnull().sum()만 생각하는데 이렇게 하면 column별로 이상치를 판단하게 된다

 

df.isnull().sum()

0    0
1    1
2    2
3    2
dtype: int64

 

그런데 문제는 행 별로 이상치를 판단하고자 한다

 

구체적으로 행 안에 2개이상의 이상치가 있으면 제거하고 싶다

 

첫번째 방법

 

df.values로 행을 모아온 다음에 하나씩 이상치의 개수를 판단한다

 

np.isnan()을 사용하면 numpy array안에 이상치가 존재하면 그 이상치를 True로 표시하고 아니면 False로 표시한 array를 출력

 

np.isnan(np.array([1,2,3,np.nan,3,4]))
array([False, False, False,  True, False, False])

np.isnan(np.array([3,np.nan,np.nan,4,5,2,1]))
array([False,  True,  True, False, False, False, False])

 

그러면 .sum()을 붙이면 아마 True의 개수를 셀거임

 

np.isnan(np.array([1,2,3,np.nan,3,4])).sum()
1

np.isnan(np.array([3,np.nan,np.nan,4,5,2,1])).sum()
2

 

그래서 이걸 이용해서 df.values로 row 하나씩 반복문을 돌고

 

이상치가 2개 이상인 row의 index를 가져올거

del_ind = []

for ind,row in enumerate(df.values):
    
    if np.isnan(row).sum() >= 2:
        
        del_ind.append(ind)

 

 

이러면 이상한 에러가 난다

 

왜 나는지 확인해보니까

 

np.isnan()은 np.float64같은 np의 dtype에만 사용가능하다고함

 

dtype=object면 에러난다고함

 

['xdjwew1235453kdrew', 75.0, nan, nan] 데이터프레임의 row들을 보면 첫번째에 문자열때문에 에러가 나는것 같다

 

df.values[1]
array(['jgierw0548323kgfe', 54.0, 36.0, 89.0], dtype=object)

np.array([1,2,3,np.nan,3,4]).dtype
dtype('float64')

 

반면 pd.isnull()은 np타입은 당연히 사용가능하고 dtype=object여도 에러가 안난다고 한다

 

del_ind = []

for ind,row in enumerate(df.values):
    
    if pd.isnull(row).sum() >= 2:
        
        del_ind.append(ind)

del_ind
[0,4]

 

df.drop(<index list>)를 하면 df에서 <index list>가 지정한 행들을 제거한다

 

 

두번째

 

이거 복기하다가 생각났는데

 

sum()에 axis연산을 사용하면 행별로 합을 할수가 있다는거 생각남

 

df.isnull().sum(axis=1)을 하면 df.isnull()에서 행별로 sum()을 해서

 

df.isnull().sum(axis=1)
0    2
1    0
2    1
3    0
4    2
dtype: int64

 

바로 이렇게 행별로 이상치의 개수를 구할 수 있음

 

outlier = df.isnull().sum(axis=1)

del_ind = []

for ind,a in enumerate(outlier):
    
    if a >= 2:
        
        del_ind.append(ind)

del_ind
[0,4]

 

근데 큰 차이는 없는데??? 뭐 아무튼 df.drop(del_ind)하면 이상치가 2개 이상인 행이 제거될거임

 

 

4. 중위수로 이상치 채우기

 

pd.fillna(<value>)함수를 사용하면 NaN에 지정한 value로 채운다

 

<value>에 df.median()을 쓰면 열별로 median을 구한다음에 그 median으로 해당 열에 NaN값을 채워넣는다

 

df.mean()은 열별 평균으로 채우고...

 

 

5. 가중평균을 구한다음에 새로운 column을 만들기

 

변수 1의 값은 0.5배, 변수 2의 값은 0.3배, 변수 3의 값은 0.2배한 가중평균을 변수 4로 만들어 저장

 

df.value로 각 row를 불러 온 다음에 row[1]*0.5+row[2]*0.3+row[3]*0.2를 리스트로 만들어서

 

df[4]에 저장

 

weight = []

for row in df_med.values:
    
    weight.append(row[1]*0.5+row[2]*0.3+row[3]*0.2)

weight
[80.8, 55.599999999999994, 54.8, 95.60000000000001, 68.75]

df_med[4] = weight
df_med

 

 

6. 문자열에서 숫자만 추출하기

 

정규표현식 사용

 

re 모듈에서 re.findall 함수를 사용

 

'[0-9]'는 0부터 9중 하나를 의미함

 

re.findall('[0-9]',s)를 이용하면 s안에 들어간 0부터 9중 하나씩 모두 가져온다음 리스트로 반환함

 

''.join(<list>)를 하면 <list>를 합친 문자열로 반환함

 

import re

s= df_med[0][0]
s
'xdjwew1235453kdrew'

re.findall('[0-9]',s)
['1', '2', '3', '5', '4', '5', '3']

''.join(re.findall('[0-9]',s))
'1235453'

 

그러면 0번 변수를 df_med[0]으로 가져온 다음에 for문으로 하나씩 빼서

 

re.findall()함수를 이용하면 숫자로만 변환할 수 있음

 

그렇게 만든 리스트를 df_med[0]에 다시 저장하면

 

str_list = []

for id_str in df_med[0]:
    
    str_list.append(''.join(re.findall('[0-9]',id_str)))

str_list
['1235453', '0548323', '3058372', '02853', '29584034']

 

 

 

7. 특정 변수 기준으로 정렬하기

 

4번 변수 값을 기준으로 내림차순 정렬

 

그리고 4번 변수 값이 70.0 이상인 0번 변수 값들을 데이터프레임으로 출력

 

df.sort_values(by=<column>, ascending=True)

 

 

ascending의 기본값은 True라서 내림차순 정렬할려면 ascending=False로 지정

 

 

fancy indexing을 이용해서 4번 변수 값 df_med[4] >=70.0인 값을 출력

 

df_med[df_med[4]>=70.0][0]을 하면 df_med[4]>=70.0인 0번 변수 값들을 Series로 가져온다

 

이걸 pd.DataFrame으로 데이터프레임으로 바꾸면

 

df_med_sort = df_med.sort_values(by=4,ascending=False)

pd.DataFrame(df_med_sort[df_med_sort[4]>=70.0][0])

 

 

 

 

출처

 

https://stackoverflow.com/questions/36000993/numpy-isnan-fails-on-an-array-of-floats-from-pandas-dataframe-apply

 

Numpy isnan() fails on an array of floats (from pandas dataframe apply)

I have an array of floats (some normal numbers, some nans) that is coming out of an apply on a pandas dataframe. For some reason, numpy.isnan is failing on this array, however as shown below, each

stackoverflow.com

 

 

'프로그래밍 > Pandas' 카테고리의 다른 글

Pandas 기초 9편  (0) 2024.01.03
Pandas 기초 8편  (0) 2021.12.02
Pandas 기초 7편  (0) 2021.12.02
Pandas 기초 6편  (0) 2021.11.25
Pandas 기초 5편  (0) 2021.11.25
TAGS.

Comments