transform 메소드로 결측치에 그룹별 평균값 대입하기¶
1. df.transform(함수)¶
칼럼/로우 혹은 데이터프레임 전체에 해당 함수를 적용한 결과 값을 원본과 같은 형태의 시리즈 혹은 데이터프레임으로 반환한다.
In [1]:
import pandas as pd
import numpy as np
In [7]:
df = pd.DataFrame(np.arange(1, 21).reshape(4,5), columns=list('abcde'))
df
Out[7]:
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 |
1 | 6 | 7 | 8 | 9 | 10 |
2 | 11 | 12 | 13 | 14 | 15 |
3 | 16 | 17 | 18 | 19 | 20 |
In [8]:
# 컬럼에만 적용하면 같은 형태의 시리즈 반환
df['e'].transform(np.sqrt)
Out[8]:
0 2.236068
1 3.162278
2 3.872983
3 4.472136
Name: e, dtype: float64
In [9]:
type(df['e'].transform(np.sqrt))
Out[9]:
pandas.core.series.Series
In [10]:
# 데이터프레임 전체에 적용하면 같은 형태의 데이터프레임 반환
df.transform(lambda x : x**2)
Out[10]:
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 1 | 4 | 9 | 16 | 25 |
1 | 36 | 49 | 64 | 81 | 100 |
2 | 121 | 144 | 169 | 196 | 225 |
3 | 256 | 289 | 324 | 361 | 400 |
In [11]:
type(df.transform(lambda x : x**2))
Out[11]:
pandas.core.frame.DataFrame
2.. 그룹이 한 종류인 경우¶
In [20]:
# 그룹이 한 개인 데이터프레임 생성
df1 = pd.DataFrame({'grp': list('a'*4 + 'b'*4), 'col_1': np.random.randint(0, 20, 8)})
df1
Out[20]:
grp | col_1 | |
---|---|---|
0 | a | 1 |
1 | a | 6 |
2 | a | 13 |
3 | a | 16 |
4 | b | 12 |
5 | b | 1 |
6 | b | 6 |
7 | b | 0 |
In [21]:
# 결측치 생성
df1.iloc[[3, 7], 1] = np.nan
df1
Out[21]:
grp | col_1 | |
---|---|---|
0 | a | 1.0 |
1 | a | 6.0 |
2 | a | 13.0 |
3 | a | NaN |
4 | b | 12.0 |
5 | b | 1.0 |
6 | b | 6.0 |
7 | b | NaN |
In [38]:
# 그룹별 평균 확인
df1.groupby('grp')['col_1'].mean()
Out[38]:
grp
a 6.666667
b 6.333333
Name: col_1, dtype: float64
In [42]:
# groupby를 적용한 후 transform을 적용하면 col_1의 각 요소에 mean을 적용한 시리즈를 반환
df1.groupby('grp')['col_1'].transform('mean')
Out[42]:
0 6.666667
1 6.666667
2 6.666667
3 6.666667
4 6.333333
5 6.333333
6 6.333333
7 6.333333
Name: col_1, dtype: float64
In [43]:
# 이 값을 col_1의 결측치에 대입
df1['col_1'] = df1['col_1'].fillna(df1.groupby('grp')['col_1'].transform('mean'))
df1
Out[43]:
grp | col_1 | |
---|---|---|
0 | a | 1.000000 |
1 | a | 6.000000 |
2 | a | 13.000000 |
3 | a | 6.666667 |
4 | b | 12.000000 |
5 | b | 1.000000 |
6 | b | 6.000000 |
7 | b | 6.333333 |
In [44]:
# groupby로 묶은 다음 ['col_1']을 지정하지 않으면 데이터프레임을 반환 -> fillna로 결측치에 대입 불가
df1.groupby('grp').transform('mean')
Out[44]:
col_1 | |
---|---|
0 | 6.666667 |
1 | 6.666667 |
2 | 6.666667 |
3 | 6.666667 |
4 | 6.333333 |
5 | 6.333333 |
6 | 6.333333 |
7 | 6.333333 |
In [45]:
type(df1.groupby('grp').transform('mean'))
Out[45]:
pandas.core.frame.DataFrame
3.. 그룹이 두 종류인 경우¶
In [27]:
# 두 종류의 그룹([grp : a, b], [num : 1, 2, 3])이 있는 데이터프레임 생성
df2 = pd.DataFrame({'grp': list('a'*9 + 'b'*9), 'num': list('123'*6), 'col_1': np.random.randint(0, 20, 18)})
df2
Out[27]:
grp | num | col_1 | |
---|---|---|---|
0 | a | 1 | 4 |
1 | a | 2 | 19 |
2 | a | 3 | 8 |
3 | a | 1 | 8 |
4 | a | 2 | 3 |
5 | a | 3 | 8 |
6 | a | 1 | 8 |
7 | a | 2 | 16 |
8 | a | 3 | 7 |
9 | b | 1 | 18 |
10 | b | 2 | 7 |
11 | b | 3 | 18 |
12 | b | 1 | 11 |
13 | b | 2 | 15 |
14 | b | 3 | 10 |
15 | b | 1 | 11 |
16 | b | 2 | 10 |
17 | b | 3 | 0 |
In [28]:
# 결측치 생성
df2.iloc[[0, 4, 8, 9, 13, 17], 2] = np.nan
df2
Out[28]:
grp | num | col_1 | |
---|---|---|---|
0 | a | 1 | NaN |
1 | a | 2 | 19.0 |
2 | a | 3 | 8.0 |
3 | a | 1 | 8.0 |
4 | a | 2 | NaN |
5 | a | 3 | 8.0 |
6 | a | 1 | 8.0 |
7 | a | 2 | 16.0 |
8 | a | 3 | NaN |
9 | b | 1 | NaN |
10 | b | 2 | 7.0 |
11 | b | 3 | 18.0 |
12 | b | 1 | 11.0 |
13 | b | 2 | NaN |
14 | b | 3 | 10.0 |
15 | b | 1 | 11.0 |
16 | b | 2 | 10.0 |
17 | b | 3 | NaN |
In [46]:
# 그룹별 평균 확인
# 첫번째 결측치에는 그룹(a, 1) 그룹의 평균, 두번째 결측치에는 그룹(a, 2)의 평균 ... 마지막 결측치에는 (b, 3) 그룹의 평균 대입
df2.groupby(['grp','num'])['col_1'].mean()
Out[46]:
grp num
a 1 8.0
2 17.5
3 8.0
b 1 11.0
2 8.5
3 14.0
Name: col_1, dtype: float64
In [47]:
# groupby 적용한 col_1에 transform을 적용하면 col_1의 각 요소에 mean을 적용한 시리즈를 반환한다.
df2.groupby(['grp','num'])['col_1'].transform('mean')
Out[47]:
0 8.0
1 17.5
2 8.0
3 8.0
4 17.5
5 8.0
6 8.0
7 17.5
8 8.0
9 11.0
10 8.5
11 14.0
12 11.0
13 8.5
14 14.0
15 11.0
16 8.5
17 14.0
Name: col_1, dtype: float64
In [49]:
# 이 값을 기존의 col_1 결측치에 대입
df2['col_1'] = df2['col_1'].fillna(df2.groupby(['grp','num'])['col_1'].transform('mean'))
df2
Out[49]:
grp | num | col_1 | |
---|---|---|---|
0 | a | 1 | 8.0 |
1 | a | 2 | 19.0 |
2 | a | 3 | 8.0 |
3 | a | 1 | 8.0 |
4 | a | 2 | 17.5 |
5 | a | 3 | 8.0 |
6 | a | 1 | 8.0 |
7 | a | 2 | 16.0 |
8 | a | 3 | 8.0 |
9 | b | 1 | 11.0 |
10 | b | 2 | 7.0 |
11 | b | 3 | 18.0 |
12 | b | 1 | 11.0 |
13 | b | 2 | 8.5 |
14 | b | 3 | 10.0 |
15 | b | 1 | 11.0 |
16 | b | 2 | 10.0 |
17 | b | 3 | 14.0 |
'파이썬 팁' 카테고리의 다른 글
list.sort()와 sorted()의 차이, key 인자 활용 (0) | 2022.12.04 |
---|---|
클래스, 메소드 정보 조회하기 (0) | 2022.12.01 |
결측치에 그룹별 최빈값 대입하기 (0) | 2022.11.27 |
zip 함수의 활용 (0) | 2022.11.18 |
조건에 맞는 데이터에 값 대입 (0) | 2022.11.11 |
댓글