min/max/mean등은 groupby의 전체 Series 데이터로는 사용할 수 없다.

groupby 와 transform을 사용해서 전체 Series 에 대한 값을 설정할 수 있다.

 

import pandas as pd
import numpy as np

df = pd.read_csv("diabetes.csv")

# 혈압 인슐린 BMI, 피부 두께가 0인 데이터들이 있다.
# 값이 비정상적이라, 0인 값을 None으로 대체하고 전체 평균으로 fillna하는 것보다
# 나이대별 평균으로 fillna를 한다고 한다면.(우선 혈압데이터에 대해 진행한다)
df.describe()
# Pregnancies	Glucose	BloodPressure	SkinThickness	Insulin	BMI	DiabetesPedigreeFunction	Age	Outcome
# count	768.000000	768.000000	768.000000	768.000000	768.000000	768.000000	768.000000	768.000000	768.000000
# mean	3.845052	120.894531	69.105469	20.536458	79.799479	31.992578	0.471876	33.240885	0.348958
# std	3.369578	31.972618	19.355807	15.952218	115.244002	7.884160	0.331329	11.760232	0.476951
# min	0.000000	0.000000	0.000000	0.000000	0.000000	0.000000	0.078000	21.000000	0.000000
# 25%	1.000000	99.000000	62.000000	0.000000	0.000000	27.300000	0.243750	24.000000	0.000000
# 50%	3.000000	117.000000	72.000000	23.000000	30.500000	32.000000	0.372500	29.000000	0.000000
# 75%	6.000000	140.250000	80.000000	32.000000	127.250000	36.600000	0.626250	41.000000	1.000000
# max	17.000000	199.000000	122.000000	99.000000	846.000000	67.100000	2.420000	81.000000	1.000000


# 1. 10대 20대로 분류되는 컬럼을 생성한다.
df["Ages"] = df.Age//10*10

# 2. 혈압이 0인 데이터를 None으로 대체한다.
df.BloodPressure = np.where(df.BloodPressure == 0, None, df.BloodPressure)

# 3. null data는 35개가 있다.
df.BloodPressure.isna().sum()
# 35

# 4. 이후 확인을 위해 null index를 따로 저장한다.
naidx = df[df.BloodPressure.isna()].index

# 5. null data는 아래와 같이 확인 가능하다.
df.loc[naidx,"BloodPressure"].head(10)
# 7      None
# 15     None
# 49     None
# 60     None
# 78     None
# 81     None
# 172    None
# 193    None
# 222    None
# 261    None
# Name: BloodPressure, dtype: object

# 만약 나이대별 평균값을 가지는 column을 생성하려고 아래와 같이 실행하면
# index 개수가 맞지 않아 정상적으로 데이터가 생성되지 않는다. 특정 index만 비정상인 값이 생성된다.
# df["AgeMeanBP"] = df.groupby("Ages").BloodPressure.mean()

# 전체 데이터가 768개인데 7개의 index만 출력된다.
# 이런 경우 mean결과를 별도 저장하고, 전체 데이터와 merge기능을 이용해서 컬럼을 생성해야하는 복잡한 과정이 필요하다.
df.groupby("Ages").BloodPressure.mean()
#Ages
#20    68.824468
#30    73.685897
#40    77.212389
#50    79.807018
#60    78.275862
#70    82.000000
#80    74.000000
#Name: BloodPressure, dtype: float64


# 이런경우 transform으로 생성하면 각 index별 그룹별 평균값을 생성할 수 있다.
# 6. 그룹별 혈압 평균을 저장하는 768개의 index를 가지는 컬럼을 생성한다.
df["AgeMeanBP"] = df.groupby("Ages").BloodPressure.transform("mean")

# null값만 확인하면 위에서 확인한 연령대별 평균이 정상적으로 생성되어있음을 확인 할 수 있다.
df.loc[naidx,["Ages","BloodPressure","AgeMeanBP"]].head(10)
#		Ages	BloodPressure	AgeMeanBP
#7		20		None			68.824468
#15		30		None			73.685897
#49		20		None			68.824468
#60		20		None			68.824468
#78		20		None			68.824468
#81		20		None			68.824468
#172	20		None			68.824468
#193	40		None			77.212389
#222	30		None			73.685897
#261	20		None			68.824468

# 7. fillna로 AgeMeanBP 를 지정하면 None value에 AgeMeanBP 값으로 추가한다.
df.BloodPressure.fillna(df.AgeMeanBP, inplace=True)
df.loc[naidx,["Ages","BloodPressure","AgeMeanBP"]].head(10)# fillna가 정상적으로 되었는지 확인
#		Ages	BloodPressure	AgeMeanBP
#7		20		68.824468		68.824468
#15		30		73.685897		73.685897
#49		20		68.824468		68.824468
#60		20		68.824468		68.824468
#78		20		68.824468		68.824468
#81		20		68.824468		68.824468
#172	20		68.824468		68.824468
#193	40		77.212389		77.212389
#222	30		73.685897		73.685897
#261	20		68.824468		68.824468

# 그룹별 평균 혈압 컬럼을 생성하지 않고, lambda식으로 한번에 생성도 가능하다.
# 다시 null 값을 원복한다.
df.loc[naidx,"BloodPressure"] = None
df.loc[naidx,["Ages","BloodPressure","AgeMeanBP"]].head(10) # 다시 null
#		Ages	BloodPressure	AgeMeanBP
#7		20		None			68.824468
#15		30		None			73.685897
#49		20		None			68.824468
#60		20		None			68.824468
#78		20		None			68.824468
#81		20		None			68.824468
#172	20		None			68.824468
#193	40		None			77.212389
#222	30		None			73.685897
#261	20		None			68.824468

# transform에 lambda식으로 평균을 입력하면 AgeMeanBP 칼럼 없이, 그룹별 혈압 평균입력이 가능하다.
df.BloodPressure = df.groupby("Ages").BloodPressure.transform(lambda x : x.fillna(x.mean()))

df.loc[naidx,["Ages","BloodPressure","AgeMeanBP"]].head(10) # 값이 정상적으로 입력
#		Ages	BloodPressure	AgeMeanBP
#7		20		68.824468		68.824468
#15		30		73.685897		73.685897
#49		20		68.824468		68.824468
#60		20		68.824468		68.824468
#78		20		68.824468		68.824468
#81		20		68.824468		68.824468
#172	20		68.824468		68.824468
#193	40		77.212389		77.212389
#222	30		73.685897		73.685897
#261	20		68.824468		68.824468

 

'전처리' 카테고리의 다른 글

Pandas 구간화 bining(cut, qcut)  (0) 2023.06.21
Pandas groupby section5 unstack  (0) 2023.06.21
Pandas groupby section3 (agg)  (0) 2023.06.20
Pandas groupby section2(Multi Key)  (0) 2023.06.20
Pandas groupby section1  (0) 2023.06.20

+ Recent posts