티스토리 뷰
#15 판다스 chapter 15. apply 메서드 활용
apply 메서드 활용
- 간단한 함수 만들기
함수의 기본 코드는 다음과 같다.
1) 제곱 함수는 아래와 같다.
def my_sq(x):
return x ** 2
2) n 제곱 함수 my_exp는 다음과 같다.
def my_exp(x,n):
return x ** n
과정 1~2에서 만든 함수를 사용해 보자.
print(my_sq(4))
16
print(my_exp(2,4))
16
- apply 메서드 사용하기 - 기초
- 시리즈와 데이터프레임에 apply 메서드 사용하기
1) 시리즈와 aplly 메서드
먼저 실습에 사용할 때 데이터프레임을 준비합니다.
import pandas as pd
df = pd.DataFrame({'a': [10,20,30], 'b': [20,30,40]})
print(df)
a b
0 10 20
1 20 30
2 30 40
2) 다음은 앞에서 만든 제곱함수(my_exp)를 사용하기 전에 a 열을 제곱하여 얻은 결과이다. 이 결괏값과 apply 메서드를 적용한 결괏값을 비교해 보자.
print(df['a'] ** 2)
0 100
1 400
2 900
Name: a, dtype: int64
3) 다음은 apply 메서드에 제곱 함수의 이름(my_sq)을 전달하여 시리즈의 모든 데이터에 제곱 함수를 적용한 것이다. 이때 apply 메서드에 전달하는 함수(my_sq)가 1개의 인자를 받도록 구성되어 있다면 인잣값을 생략해야 한다. 그러면 2개의 인자를 전달해야 할 경우엔 어떻게 해야할까?
sq = df['a'].apply(my_sq)
print(sq)
0 100
1 400
2 900
Name: a, dtype: int64
4) 이제 2개의 인자를 전달받아야 하는 n 제곱 함수(my_exp)와 apply 메서드를 함께 사용해 보자. apply 메서드의 첫 번째 인자에는 n 제곱 함수의 이름을 전달하고 두 번째 인자에는 n 제곱 함수의 두 번째 인자를 전달한다.
ex = df['a'].apply(my_exp, n=2)
print(ex)
0 100
1 400
2 900
Name: a, dtype: int64
ex = df['a'].apply(my_exp, n=3)
print(ex)
0 1000
1 8000
2 27000
Name: a, dtype: int64
5) 데이터프레임과 apply 메서드
이번엔 시리즈가 아니라 데이터프레임에 apply 메서드를 사용하는 방법을 알아보자. 우선 데이터프레임을 먼저 준비하자.
df = pd.DataFrame({'a': [10,20,30], 'b': [20,30,40]})
print(df)
a b
0 10 20
1 20 30
2 30 40
6) 새로운 함수를 만들어보자. 이번에 사용할 함수는 1개의 값을 전달받아 출력하는 함수이다.
def print_me(x):
print(x)
7) 이번엔 데이터프레임에 함수를 적용해야 하기 때문에 함수를 열 방향으로 적용할지 행 방향으로 적용할지 정해야 한다. axis 인잣값을 0이나 1로 지정하면 함수를 열 또는 행 방향으로 적용할 수 있다.
print(df.apply(print_me, axis=0))
0 10
1 20
2 30
Name: a, dtype: int64
0 20
1 30
2 40
Name: b, dtype: int64
a None
b None
dtype: object
print(df['a'])
0 10
1 20
2 30
Name: a, dtype: int64
print(df['b'])
0 20
1 30
2 40
Name: b, dtype: int64
8) 이번엔 3개의 인자를 입력받아 평균을 계산하는 함수를 사용해 보자.
def avg_3(x,y,z):
return (x+y+z) / 3
9) 그런데 avg_3 함수를 apply 메서드에 전달하면 'avg_3 함수는 3개의 인잣값을 필요로 하는 함수인데 1개의 인잣값만 입력받았다' 라는 오류 메세지가 아래와 같이 출력된다. 즉, avg_3 함수에 열 단위 데이터가 전달 되었고 이 값을 avg_3 함수에서 1개의 인자로 인식한 것이다. 따라서 avg_3 함수가 열 단위로 데이터를 처리할 수 있도록 수정해야 한다.
print(df.apply(avg_3))
TypeError: avg_3() missing 2 required positional arguments: 'y' and 'z'
10) 다음은 avg_3 함수가 열 단위로 데이터를 처리할 수 있도록 개선한 avg_3_apply 함수이다. 개선한 함수를 apply 메서드에 적용하면 잘 동작하는 것을 볼 수 있다.
def avg_3_apply(col):
x = col[0]
y = col[1]
z = col[2]
return (x+y+z) / 3
print(df.apply(avg_3_apply))
a 20.0
b 30.0
dtype: float64
11) 앞의 과정에서 데이터프레임의 행 개수가 3이라는 것을 알고 있다는 전제하에 avg_3_apply 함수를 작성했다. 하지만 일반적으로는 아래와 같이 for문을 이용하여 작성한다.
def avg_3_apply(col):
sum = 0
for item in col:
sum += item
return sum / df.shape[0]
12) 과정 11의 함수를 응용하면 행 방향으로 데이터를 처리하는 함수도 만들 수 있다. 마지막 return문의 df.shape[1]로 바꾸면 된다.
def avg_2_apply(row):
sum = 0
for item in row:
sum += item
return sum / df.shape[1]
print (df.apply(avg_2_apply, axis =1))
0 15.0
1 25.0
2 35.0
dtype: float64
apply 메서드 사용하기 - 고급
- 데이터프레임의 누락값을 처리한 다음 apply 메서드 사용하기
1) 데이터프레임의 누락값 처리하기 - 열 방향
이번에도 seaborn 라이브러리에 있는 데이터를 사용하자. seaborn 라이브러리에 있는 titanic 데이터 집합을 불러와 변수 titanic에 저장하자.
import seaborn as sns
titanic = sns.load_dataset("titanic")
2) 다음은 titanic 데이터프레임의 데이터 정보를 출력한 것이다.
print(titanic.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 survived 891 non-null int64
1 pclass 891 non-null int64
2 sex 891 non-null object
3 age 714 non-null float64
4 sibsp 891 non-null int64
5 parch 891 non-null int64
6 fare 891 non-null float64
7 embarked 889 non-null object
8 class 891 non-null category
9 who 891 non-null object
10 adult_male 891 non-null bool
11 deck 203 non-null category
12 embark_town 889 non-null object
13 alive 891 non-null object
14 alone 891 non-null bool
dtypes: bool(2), category(2), float64(2), int64(4), object(5)
memory usage: 80.7+ KB
None
3) 다음은 누락값의 개수를 반환하는 count_missing 함수입니다. 판다스의 isnull 메서드에 데이터프레임을 전달하면 누락값의 유무에 따라 True, False를 적용한 데이터프레임이 만들어진다. 이 값을 넘파이의 sum 메서드에 전달하면 누락값의 개수를 구할 수 있다.
import numpy as np
def count_missing(vec):
null_vec = pd.isnull(vec)
null_count = np.sum(null_vec)
return null_count
4) 다음은 apply 메서드에 count_missing 함수를 전달하여 얻은 값이다.
cmis_col = titanic.apply(count_missing)
print(cmis_col)
cmis_col = titanic.apply(count_missing)
print(cmis_col)
cmis_col = titanic.apply(count_missing)
print(cmis_col)
survived 0
pclass 0
sex 0
age 177
sibsp 0
parch 0
fare 0
embarked 2
class 0
who 0
adult_male 0
deck 688
embark_town 2
alive 0
alone 0
dtype: int64
5) 다음은 누락값의 비율을 계산하는 prop_missing 함수이다. 과정 3에서 작성한 count_missing 함수를 이용해 데이터프레임의 누락값 개수를 구하고 size 속성을 이용해 데이터프레임의 전체 데이터 수를 구하여 나누면 누락값의 비율을 계산할 수 있다.
def prop_missing(vec):
num = count_missing(vec)
dem = vec.size
return num/dem
6) 다음은 apply 메서드에 prop_missing 함수를 적용한 것이다.
pmis_col = titanic.apply(prop_missing)
print(pmis_col)
survived 0.000000
pclass 0.000000
sex 0.000000
age 0.198653
sibsp 0.000000
parch 0.000000
fare 0.000000
embarked 0.002245
class 0.000000
who 0.000000
adult_male 0.000000
deck 0.772166
embark_town 0.002245
alive 0.000000
alone 0.000000
dtype: float64
7) 과정 5에서 작성한 prop_missing 함수를 이용하면 누락값이 아닌 데이터의 비율도 구할 수 있다. 전체 비율에서 누락값의 비율을 빼면 된다. 과정 5~6 과 같은 방법으로 apply 메서드에 prop_complete 함수를 전달하여 결과를 확인해 보자.
def prop_complete(vec):
return 1 - prop_missing(vec)
8) 데이터프레임의 누락값 처리하기 -- 행 방향
이번엔 행 방향으로 데이터를 처리해 보자. 다음은 axis를 1로 설정하여 앞에서 만든 count_missing, prop_missing, prop_complete 함수를 행 방향으로 적용하여 실행한 것이다. 각 행의 누락값과 누락값의 비율, 누락값이 아닌 값의 비율을 잘 계산하고 있다는 것을 알 수 있다.
cmis_row = titanic.apply(count_missing, axis=1)
pmis_row = titanic.apply(prop_missing, axis=1)
pcom_row = titanic.apply(prop_complete, axis=1)
print(cmis_row.head())
0 1
1 0
2 1
3 0
4 1
dtype: int64
print(pmis_row.head())
0 0.066667
1 0.000000
2 0.066667
3 0.000000
4 0.066667
dtype: float64
print(pcom_row.head())
0 0.933333
1 1.000000
2 0.933333
3 1.000000
4 0.933333
dtype: float64
9) 다음은 누락값의 개수를 구하여 titanic 데이터프레임에 추가한 것이다. 데이터프레임에 num_missing 열이 추가된 것을 알 수 있다.
titanic['num_missing'] = titanic.apply(count_missing, axis=1)
print(titanic.head())
survived pclass sex age sibsp parch fare embarked class \
0 0 3 male 22.0 1 0 7.2500 S Third
1 1 1 female 38.0 1 0 71.2833 C First
2 1 3 female 26.0 0 0 7.9250 S Third
3 1 1 female 35.0 1 0 53.1000 S First
4 0 3 male 35.0 0 0 8.0500 S Third
who adult_male deck embark_town alive alone num_missing
0 man True NaN Southampton no False 1
1 woman False C Cherbourg yes False 0
2 woman False NaN Southampton yes True 1
3 woman False C Southampton yes False 0
4 man True NaN Southampton no True 1
10) 과정 9에서 누락값이 있는 데이터를 데이터프레임에 추가했기 때문에 누락값이 있는 데이터만 따로 모아서 볼 수도 있다. 다음은 누락값이 2개 이상인 데이터를 추출한 것이다.
print(titanic.loc[titanic.num_missing > 1, :].sample(10))
survived pclass sex age sibsp parch fare embarked class \
826 0 3 male NaN 0 0 56.4958 S Third
596 1 2 female NaN 0 0 33.0000 S Second
511 0 3 male NaN 0 0 8.0500 S Third
61 1 1 female 38.0 0 0 80.0000 NaN First
295 0 1 male NaN 0 0 27.7208 C First
629 0 3 male NaN 0 0 7.7333 Q Third
264 0 3 female NaN 0 0 7.7500 Q Third
358 1 3 female NaN 0 0 7.8792 Q Third
859 0 3 male NaN 0 0 7.2292 C Third
613 0 3 male NaN 0 0 7.7500 Q Third
who adult_male deck embark_town alive alone num_missing
826 man True NaN Southampton no True 2
596 woman False NaN Southampton yes True 2
511 man True NaN Southampton no True 2
61 woman False B NaN yes True 2
295 man True NaN Cherbourg no True 2
629 man True NaN Queenstown no True 2
264 woman False NaN Queenstown no True 2
358 woman False NaN Queenstown yes True 2
859 man True NaN Cherbourg no True 2
613 man True NaN Queenstown no True 2
이번에는 여러가지 실습을 통해 apply 메서드가 왜 데이터 분석에 유용한지 알아 보았다.내장 함수의 기능도 훌륭하지만 때로는 나만의 함수를 만들어 데이터 처리에 사용하는 것이 더 편리할 수도 있기 때문에 apply 메서드는 반드시 알아두자!
출처 : 데이터 분석을 위한 판다스 입문
'판다스 입문' 카테고리의 다른 글
판다스 입문(그룹 연산 - 데이터필터링, 그룹 오브젝트) (0) | 2021.03.25 |
---|---|
판다스 입문(그룹연산 - 데이터집계, 데이터 변환) (0) | 2021.03.24 |
판다스 입문(문자열 처리하기) (0) | 2021.03.22 |
판다스 입문(판다스 자료형) (0) | 2021.03.21 |
판다스 입문(깔끔한 데이터 만들기) (0) | 2021.03.21 |