Python/Python기초

Python 62_ pandas_ agg vs apply

Codezoy 2020. 2. 14. 18:40


import numpy as np
import pandas as pd

np.random.seed(1)
df = pd.DataFrame({
    'pop': np.random.randint(1, 10, 4), # 1~ 10 범위의 난수 4개
    'income': np.random.randint(1, 10, 4), # 1~10 범위의 난수 4개
     }, index=['a', 'b', 'c', 'd'])
print(df)

   pop  income
a    6       1
b    9       2
c    6       8
d    1       7

# agg(aggregate): DataFrame의 축(axis)을 기준으로 통계량을 집계(aggregate)하기 위한 함수
# 통계량(statistics): 합계(sum), 평균(mean), 분산(var), 표준편차(std),
# 최솟값(min), 최댓값(max), 중앙값(median), ...
# agg 함수는 집계가 목적이기 때문에 데이터 타입이 숫자 타입인 행/열에만
# 함수를 적용해서 계산한다.


# agg 함수는 pandas나 numpy에서 제공하는 집계 함수들 이외에도
# 사용자 정의 함수를 사용할 수 있다.
# 단, 함수는 Series(여러 개의 숫자)를 파라미터에 전달하면 숫자(스칼라)를 리턴하는 함수여야 한다.

print('=== agg by column(axis = 0)')
print(df.agg('mean', axis=0))

=== agg by column(axis = 0)
pop       5.5
income    4.5
dtype: float64
print('=== agg by row(axis = 1)')
print(df.agg('mean', axis=1))

=== agg by row(axis = 1)
a    3.5
b    5.5
c    7.0
d    4.0
dtype: float64

def squared_mean(data):
    """데이터의 제곱의 평균을 리턴"""
    squared_sum=0
    for x in data:
        squared_sum += x**2
    return squared_sum / len(data)

print(df.agg(squared_mean, axis=0))

pop       38.5
income    29.5
dtype: float64


print(df.agg(squared_mean, axis=1))
a    18.5
b    42.5
c    50.0
d    25.0
dtype: float64


# apply: DataFrame에 축(axis)을 기준으로 함수를 적용(apply)하기 위한 함수
# 적용하는 함수는 pandas 객체(DataFrame, Series, 숫자 스칼라)를 리턴하면 됨.
# agg 함수는 숫자 타입의 스칼라만 리턴하는 함수를 적용하는 apply의 특수한 경우
# 집계와 같은 특수한 목적인 경우에는 agg 함수보다 성능이 느리다.

print('=== apply by column(axis=0)')
print(df.apply('mean'))

=== apply by column(axis=0)
pop       5.5
income    4.5
dtype: float64

print('=== apply by column(axis=1)')
print(df.apply('mean', axis=1))
=== apply by column(axis=1)
a    3.5
b    5.5
c    7.0
d    4.0
dtype: float64

# Series 객체 생성
np.random.seed(1)
s = pd.Series(np.random.randint(1, 10, 5))
s[3] = np.nan # 원소 한개를 NA로 변경
print(s)

0    6.0
1    9.0
2    6.0
3    NaN
4    1.0
dtype: float64

m = s.mean() # numpy, pandas의 집계 함수들은 NA를 제거하고 계산함.
print(m)
5.5

s = s.fillna(m) # 모든 NA들에 m을 삽입해준다.
print(s)

0    6.0
1    9.0
2    6.0
3    5.5
4    1.0
dtype: float64
df = pd.DataFrame({
    'province': ['서울', '경기', '충청', '전라', '강원', '경상', '부산'],
    'division': ['west']*4 + ['east']*3,
    'data': np.random.randint(1, 10, 7)
    })
print(df)
    
  province division  data
0       서울     west     2
1       경기     west     8
2       충청     west     7
3       전라     west     3
4       강원     east     5
5       경상     east     6
6       부산     east     3

# 데이터 2개를 NA로 대체
df.iloc[0,2]= np.nan
df.iloc[6,2]= np.nan
print(df)

  province division  data
0       서울     west   NaN
1       경기     west   8.0
2       충청     west   7.0
3       전라     west   3.0
4       강원     east   5.0
5       경상     east   6.0
6       부산     east   NaN

# 데이터 프레임의 NA를 각 그룹별 평균으로 대체
grouped = df.groupby('division') # DataFrameGroupBy 객체
# Groupby.apply(fn)은 함수 fn의 첫번째 파라미터에 DataFrameGroupBy 객체를 전달한다.
cleaned = grouped.apply(fill_group_mean)
print(cleaned)

    province division  data
0       서울     west   6.0
1       경기     west   8.0
2       충청     west   7.0
3       전라     west   3.0
4       강원     east   5.0
5       경상     east   6.0
6       부산     east   5.5

6 = (8+7+3)/3
5.5 = (5+6)/2