티스토리 뷰

#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 메서드는 반드시 알아두자!

 

 

출처 : 데이터 분석을 위한 판다스 입문

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함