본문 바로가기

Data Science/Pandas

pandas의 transform 함수 (apply 함수와의 차이)

728x90

판다스에서 제공하는 transform() 함수에 대해서 알아보겠습니다. 그리고 apply 함수와의 차이점도 알아보겠습니다. 

 

transform()과 apply() 함수는 보통 아래와 같은 경우에 사용하면 유용합니다.  

 

  1. Transforming values (값 변환)
  2. Combining groupby() results (groupby를 사용하여 집계 함수 적용 시) 
  3. Filtering data (데이터 필터링)
  4. Handling missing value at the group level (그룹별 특정 값으로 null 값 채울 때)

하나씩 코드로 살펴보겠습니다.

Transform

1. Transforming values: 값 변환

아래와 같은 데이터프레임으로 실습해 보겠습니다.


import pandas as pd
import numpy as np

df = pd.DataFrame({'A': [1,2,3], 'B': [10,20,30] })
df


아래 두 함수는 같은 결과를 나타냅니다. transform 함수로 각 속성 값에 10을 더하는 코드입니다. 

apply 함수도 동일한 결과를 출력합니다.


def plus_10(x):
    return x+10

df.transform(plus_10) # df.apply(plus_10)
df.transform(lambda x: x+10) # df.apply(lambda x: x+10)


아래와 같이 column 별로 다른 함수를 적용할 수 있습니다.  


# column 별로 다른 함수 적용 apply 도 가능


df.transform({
    'A': np.sqrt,
    'B': np.exp
})


 

apply 함수와의 차이 1

아래와 같이 string형 함수로 인자를 넘겨줄 때, transform 함수는 결과를 잘 출력하지만 apply 함수는 오류가 발생합니다.

 


# String function: apply 불가

df.transform('sqrt')


또한, list형 함수도 transform에는 적용가능하지만, apply 함수는 불가합니다.


# List of functions: apply 불가

df.transform([np.sqrt, np.exp])


 

 

2. groupby 함수로 집계할 때

아래와 같은 데이터프레임으로 실습을 진행해 보겠습니다.


df = pd.DataFrame({
    'key': ['a','b','c'] * 3,
    'A': np.arange(9),
    'B': [1,2,3] * 3,
})
df


 

apply 함수와의 차이 2 

아래와 같이 두 함수 모두 그룹별 함수 반환값을 반환합니다. 하지만 apply는 그룹의 개수만큼의 길이를 가지는 Series를 반환한다면,  transform 함수는 input과 동일한 길이의 Series 반환합니다.   


def group_sum(x):
    return x.sum()

df.groupby('key')['A'].transform(group_sum)

# 결과
```
0     9
1    12
2    15
3     9
4    12
5    15
6     9
7    12
8    15
Name: A, dtype: int32
```


df.groupby('key')['A'].apply(group_sum)

# 결과
```
key
a     9
b    12
c    15
Name: A, dtype: int64
```

 

아래와 같은 데이터프레임으로 더 실습해 보겠습니다. 


df = pd.DataFrame({
  'restaurant_id': [101,102,103,104,105,106,107],
  'address': ['A','B','C','D', 'E', 'F', 'G'],
  'city': ['London','London','London','Oxford','Oxford', 'Durham', 'Durham'],
  'sales': [10,500,48,12,21,22,14]
})
df


 

바로 전에 살펴본 대로 apply 함수 적용 시 그룹의 개수를 길이로 가지는 Series를 반환하고, transform 함수 적용 시, input 길이의 Series를 반환하고 있습니다.  


# city 별 sales 합

df.groupby('city')['sales'].sum().rename('city_total_sales') # apply와 같은 역할

# 결과
```
city
Durham     36
London    558
Oxford     33
Name: city_total_sales, dtype: int64
```


df.groupby('city')['sales'].transform(sum).rename('city_total_sales')

# 결과
```
0    558
1    558
2    558
3     33
4     33
5     36
6     36
Name: city_total_sales, dtype: int64
```

Tip

위의 반환값을 Series가 아닌 DataFrame으로 반환받고 싶다면 reset_index()를 추가하면 됩니다.

# dataframe으로 출력하려면
df.groupby('city')['sales'].sum().rename('city_total_sales').reset_index()

 

apply 함수로 groupby 함수를 적용하고 원래 데이터프레임에 그룹별 값을 할당하고 싶을 때는 merge나 join으로 처리해 줄 수 있습니다. 하지만 transform 함수는 원래 데이터프레임의 길이와 동일한 Series가 반환되기 때문에 바로 원래 데이터프레임에 값을 넣을 수 있습니다.

 


1. Apply

city_sales= df.groupby('city')['sales'].sum().rename('city_total_sales').reset_index() # apply와 동일

# merge로 해도 mapping 하는 효과
df_new = pd.merge(df, city_sales, how='left') # on=None(default)이면 두 데이터프레임의 공통 열  

df_new['pct'] = df_new['sales'] / df_new['city_total_sales']
df_new['pct'] = df_new['pct'].apply(lambda x: format(x, '.2%'))

df_new

   

2. Transform

# groupby & transform
df['city_total_sales'] = df.groupby('city')['sales'].transform('sum')

df['pct'] = df['sales'] / df['city_total_sales']
df['pct'] = df['pct'].transform(lambda x: format(x, '.2%'))

df

동일 결과


 

3.  Filtering data: 데이터 필터링


# filtering data

df[df.groupby('city')['sales'].transform('sum') > 40]


4. Handling missing value at the group level: group 별로 특정 값으로 null 값 채우기

아래와 같은 데이터프레임을 이용하여 transform 함수로 그룹별로 null 값을 채워보겠습니다.  


# group level로 null 값 채우기

df = pd.DataFrame({
    'name': ['A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'],
    'value': [1, np.nan, np.nan, 2,8,2,np.nan, 3]
})
df


 

df.groupby('name').transform(lambda x:x.fillna(x.mean())) # 데이터프레임으로 출력

df.groupby('name')['value'].transform(lambda x:x.fillna(x.mean())) # Series로 출력


마지막으로 apply 함수와 transform 함수의 차이점 1가지를 더 알아보겠습니다.

아래와 같이, apply 함수는 여러 개의 series와 한 번에 작업 가능하지만, transform 함수는 여러 개 series에 작업을 한 번에 적용할 수 없습니다.


def subtract_two(x):
    return x['B'] - x['A']
    
df = pd.DataFrame({'A': [1,2,3], 'B': [10,20,30] })

# transform 불가
df.apply(subtract_two, axis=1) # df.apply(lambda x: x['B'] - x['A'], axis=1) 

# 결과
```
0     9
1    18
2    27
dtype: int64
```

 

 

정리하면, apply함수와 transform 함수의 차이는 아래와 같습니다.

  • transform: input과 동일한 길이의 Series 반환, 여러 개 series와 작업 한 번에 불가
  • apply: 여러 개의 series와 한 번에 작업 가능
728x90
반응형