결측치 다루기
- 데이터 파악
null인 경우 = True
df.isnull() # 한행에 한열에 해당하는 값을 데이터 포인트라고 함.
=>
passengerid survived pclass name gender age sibsp parch ticket fare cabin embarked
0 False False False False False False False False False False True False
1 False False False False False False False False False False False False
2 False False False False False False False False False False True False
3 False False False False False False False False False False False False
4 False False False False False False False False False False True False
... ... ... ... ... ... ... ... ... ... ... ... ...
1304 False False False False False True False False False False True False
1305 False False False False False False False False False False False False
1306 False False False False False False False False False False True False
1307 False False False False False True False False False False True False
1308 False False False False False True False False False False True False
1309 rows × 12 columns
결측치 개수 확인
df.isnull().sum() #axis 기본값은 0 즉 열별로 결측지 확인가능
=>
passengerid 0
survived 0
pclass 0
name 0
gender 0
age 263
sibsp 0
parch 0
ticket 0
fare 1
cabin 1014
embarked 2
dtype: int64
- 시리즈에서 인덱스 가져오기
df.isnull().sum().index
=>
Index(['passengerid', 'survived', 'pclass', 'name', 'gender', 'age', 'sibsp',
'parch', 'ticket', 'fare', 'cabin', 'embarked'],
dtype='object')
- 시리즈에서 값들만 가져오기
df.isnull().sum().values
=>
array([ 0, 0, 0, 0, 0, 263, 0, 0, 0, 1, 1014,
2])
넘파이 사용하면 행렬로 변환한다.
df.isnull().sum().to_numpy() # 행렬로 변환한다.
=>
array([ 0, 0, 0, 0, 0, 263, 0, 0, 0, 1, 1014,
2])
- 행에 결측치가 하나라도 있으면 삭제하기는 원본 데이터 손상때문에 잘 안쓴다.
- 행에 모든 값이 결측치라면 삭제하기
df.dropna(how="all")
=> 결측치를 모두 삭제한다.
결측치 채우기
- 최빈값으로 결측치 채우기
mode_value = df["embarked"].mode()[0] # 최빈값
df["embarked"] = df["embarked"].fillna(mode_value)
최빈값으로 결측치를 채우는 경우는 범주형 데이터일 때 일반적으로 사용하고,
수치형 데이터는 평균값을 일반적으로 채운다.
그러나 이것이 모조건 답이 아니다. 상황에 따라 적용방식은 바뀔 수 있다.
특정 값들 포함 여부
- isin 메소드
# S이거나 C인 항구를 보고싶다면?
lst = ["S","C"]
mask = df["embarked"].isin(lst)
df.loc[mask]
=> S이거나 C인 항구 출력됨!
- display
display(df.head()) # display를 사용하면 2개 다 볼 수 있다.
df.info #노트북환경일 때 마지막 값말고도 위에도 볼수있다 display사용하면
타입 변환하기
df["embarked"].astype("category")
메모리를 많이 차지할땐 타입을 변환시켜 메모리를 줄여줄 수 있다.
문자열다루기
- objecct 타입의 하위 속성인 str 을 이용하여 다양한 문자열 관련 메소드를 사용할수 있다.
df["ticket"].str.split() # 리스트로 바뀜
df["ticket"].str.replace("/","_") # regex = True <= 정규표현식 옵션
df["ticket"].str.strip() #앞뒤 공백제거, lstrip, rstirp
df["name"].str.split(",",expand=True) # 데이터프레임 형태로 반환
df["name"].str.len() # 문자열 길이 측정
위에 것은 물론 슬라이싱까지 가능하다.
피벗테이블 사용해보기
- pd.pivot_table
- 데이터를 기준이 되는 컬럼을 집계하여 새롭게 표형태로 작성해주는 기능
- index: 행으로 사용할 컬럼이름
- columns: 열로 사용할 컬럼이름
- values: 집계 대상 컬럼
- aggfunc: values 에 대한 집계함수
- std, var, mean, count, sum 등등
- fill_value: Nan에 대해 채울 값
구조
group by 컬럼1(index) 컬럼2(columns)
나이대별 운임료의 평균은?
tmp = pd.pivot_table(
df, # 대상이 되는 데이터 프레임
index = "age2",
values = "fare",
aggfunc = np.mean #"mean"
) # age 밑에 0~8은 컬럼이 아님!
tmp
=>
fare
age2
0 29.310059
1 31.713172
2 23.742729
3 41.286781
4 42.396421
5 62.642201
6 69.926825
7 37.147629
8 30.000000
인덱스를 컬럼으로 옮겨서 정돈화한다.
tmp.reset_index()
=>
age2 fare
0 0 29.310059
1 1 31.713172
2 2 23.742729
3 3 41.286781
4 4 42.396421
5 5 62.642201
6 6 69.926825
7 7 37.147629
8 8 30.000000
- 각 나이대에서 pclass 별로 생존률을 알고 싶다면?
- group by age2, pclass와 비슷한 효과
tmp = pd.pivot_table(
df,
index = "age2",
columns = "pclass", # 컬럼
values = "survived",
aggfunc="mean",
# fill_value = 0 # 결측치 채움
) # 인덱스가 2개이다. 컬럼부분이 위로 올라가 있다.
tmp.reset_index()
tmp
=>
pclass age2 1 2 3
0 0 0.500000 0.909091 0.446429
1 1 0.772727 0.482759 0.315217
2 2 0.560440 0.377358 0.258537
3 3 0.694444 0.375000 0.260417
4 4 0.500000 0.387097 0.119048
5 5 0.521739 0.294118 0.000000
6 6 0.428571 0.285714 0.250000
7 7 0.250000 0.000000 0.000000
8 8 1.000000 NaN NaN
- 각 나이대에 대하여 pclass 별 운임료에 대한 표준편차와 평균을 보고싶다면?
tmp = pd.pivot_table(
df,
index = "age2",
columns = "pclass",
values = "fare",
aggfunc = ["skew",np.mean] # 최빈값 안됨!
)
tmp # 멀티 컬럼
=>
skew mean
pclass 1 2 3 1 2 3
age2
0 -1.672495 0.124216 0.595672 129.864575 29.064209 22.224177
1 1.019391 1.537841 2.274084 112.567614 25.605890 14.303536
2 1.512632 2.038175 3.730918 80.267215 19.864858 12.199623
3 2.800489 2.778215 2.968224 99.668982 19.281575 12.170268
4 1.782495 1.941873 1.791953 71.201616 23.259542 13.999305
5 3.176504 0.865329 2.508352 87.932063 16.433824 8.672029
6 1.145553 0.958788 1.180979 98.361510 19.148214 9.507300
7 -0.318243 NaN NaN 58.502100 10.500000 7.762500
8 NaN NaN NaN 30.000000 NaN NaN
컬럼을 언패킹하여 "_" 을 붙여서 새로운 열이름을 만든다.
x = []
for i,k in tmp.columns: # 언패킹 생각을 못함!
x.append(f"{i}_{k}")
tmp.columns = x
tmp.reset_index()
=>
age2 std_1 std_2 std_3 mean_1 mean_2 mean_3
0 0 32.998005 7.607598 9.931735 129.864575 29.064209 22.224177
1 1 79.479218 20.687895 12.061098 112.567614 25.605890 14.303536
2 2 68.631329 14.350426 11.735901 80.267215 19.864858 12.199623
3 3 103.214742 10.006333 9.016939 99.668982 19.281575 12.170268
4 4 61.179262 13.642985 11.209306 71.201616 23.259542 13.999305
5 5 84.418283 6.151467 2.601784 87.932063 16.433824 8.672029
6 6 88.146400 11.352616 3.571085 98.361510 19.148214 9.507300
7 7 20.165309 NaN 0.017678 58.502100 10.500000 7.762500
8 8 NaN NaN NaN 30.000000 NaN NaN
- 나이대별 pclass의 최빈값을 pivot_table로 만들어보세요.
# def do_agg(x): # 콜백 함수 사용도 가능! (생각을 못함!)
# return x.mode()
tmp = pd.pivot_table(
df,
index = "age2",
values = "pclass", # 컬럼
# aggfunc = do_agg
aggfunc = lambda x: x.mode() # 람다 생각을 못함!
)
=>
pclass
age2
0 3
1 3
2 3
3 3
4 1
5 1
6 1
7 1
8 1
최빈값을 구할 때 처음 df["pclass"].mode()로 하였는데 이것은 pclass 전체의 최빈값이므로 틀리다.
이외에도 최빈값은 따로 메소드가 없기 때문에 람다함수나 콜백함수를 사용하여 쓴다.
groupby 메소드 사용하기
- 데이터를 그룹화하여 집계해서 가공하는데 매우 중요하다.
DataFrame.groupby(<그룹핑 대상이 되는 컬럼>) ["집계대상이 되는 컬럼"].<집계 메소드>()
- 그룹핑 대상이 되는 컬럼: 문자열 혹은 리스트로 전달
예시
tmp = df.groupby("embarked")["fare"].std()
tmp.reset_index()
=>
embarked fare
0 C 84.185996
1 Q 13.616133
2 S 37.119373
- agg메소드를 이용한 방법
df.groupby("age2")["fare"].agg("mean").reset_index()
=>
age2 fare
0 0 29.310059
1 1 31.713172
2 2 23.742729
3 3 41.286781
4 4 42.396421
5 5 62.642201
6 6 69.926825
7 7 37.147629
8 8 30.000000
- groupby 결과에 대한 딕셔너리를 이용하여 집계하는 예시
DataFrame.groupby(<그룹핑대상컬럼>).agg(<딕셔너리>)
- 딕셔너리 예시
{
"집계대상컬럼": <함수 or 문자열>
}
적용
cols = ["age2","pclass"]
agg_dict = {"survived":"mean"}
tmp = df.groupby(cols).agg(agg_dict)
tmp.reset_index() # 조인 시 2개를 기준으로 해야 논리오류가 발생되지 않는다.
=>
age2 pclass survived
0 0 1 0.500000
1 0 2 0.909091
2 0 3 0.446429
3 1 1 0.772727
4 1 2 0.482759
5 1 3 0.315217
6 2 1 0.560440
7 2 2 0.377358
8 2 3 0.258537
9 3 1 0.694444
10 3 2 0.375000
11 3 3 0.260417
12 4 1 0.500000
13 4 2 0.387097
14 4 3 0.119048
15 5 1 0.521739
16 5 2 0.294118
17 5 3 0.000000
18 6 1 0.428571
19 6 2 0.285714
20 6 3 0.250000
21 7 1 0.250000
22 7 2 0.000000
23 7 3 0.000000
24 8 1 1.000000
- 집계 컬러명 정의해주기
# 항구별 운임료의 표준편차와 평균, 객실의 다양성과 객실의 최빈값
agg_dict = {
"fare":[
("운임료_표준편차","std"),
("운임료_평균","mean")
],
"cabin":[
("객실의 다양성","nunique"),
("객실_최빈값",lambda x : x.mode())
]
}
tmp = df.groupby("embarked").agg(agg_dict)
tmp
=>
fare cabin
운임료_표준편차 운임료_평균 객실의 다양성 객실_최빈값
embarked
C 84.185996 62.336267 84 UNK
Q 13.616133 12.409012 4 UNK
S 37.119373 27.519476 105 UNK
[ ]안에 ( )를 넣으면 명칭을 바꿀 수 있다.
데이터 프레임 병합하기
- concat
- 수직 또는 수평으로 병합
- pd.concat 함수에 데이터프레임 객체들을 리스트에 담아서 전달
예시
pd.concat([df,df],axis = 1) # 옆으로 합침! 기본으로 axis = 0이다.
=>
passengerid survived pclass name gender age sibsp parch ticket fare ... name gender age sibsp parch ticket fare cabin embarked age2
0 1 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.2500 ... Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.2500 UNK S 2
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38 1 0 PC 17599 71.2833 ... Cumings, Mrs. John Bradley (Florence Briggs Th... female 38 1 0 PC 17599 71.2833 C85 C 3
2 3 1 3 Heikkinen, Miss. Laina female 26 0 0 STON/O2. 3101282 7.9250 ... Heikkinen, Miss. Laina female 26 0 0 STON/O2. 3101282 7.9250 UNK S 2
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1000 ... Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1000 C123 S 3
4 5 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.0500 ... Allen, Mr. William Henry male 35 0 0 373450 8.0500 UNK S 3
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1304 1305 0 3 Spector, Mr. Woolf male 28 0 0 A.5. 3236 8.0500 ... Spector, Mr. Woolf male 28 0 0 A.5. 3236 8.0500 UNK S 2
1305 1306 1 1 Oliva y Ocana, Dona. Fermina female 39 0 0 PC 17758 108.9000 ... Oliva y Ocana, Dona. Fermina female 39 0 0 PC 17758 108.9000 C105 C 3
1306 1307 0 3 Saether, Mr. Simon Sivertsen male 38 0 0 SOTON/O.Q. 3101262 7.2500 ... Saether, Mr. Simon Sivertsen male 38 0 0 SOTON/O.Q. 3101262 7.2500 UNK S 3
1307 1308 0 3 Ware, Mr. Frederick male 28 0 0 359309 8.0500 ... Ware, Mr. Frederick male 28 0 0 359309 8.0500 UNK S 2
1308 1309 0 3 Peter, Master. Michael J male 28 1 1 2668 22.3583 ... Peter, Master. Michael J male 28 1 1 2668 22.3583 UNK C 2
1309 rows × 26 columns
- merge
- 매우 자주 사용된다.
- how 기본값은 inner(교집합)이다.
pd.merge(<left df>,<right df>,on = "기준 컬럼", how="left")
- 머지되는 컬럼이 다수인 경우
# 각 항구에 대하여 pclass 별 운임료의 평균과 티켓의 다양성을 집계한 결과를 특성으로 추가!
agg_dict = {
"fare":"mean", # 운임료의 평균
"ticket":"nunique" # 티켓의 다양성
}
tmp = df.groupby(["embarked","pclass"]).agg(agg_dict)
tmp = tmp.add_prefix("feature_").reset_index()
tmp
=>
embarked pclass feature_fare feature_ticket
0 C 1 106.845330 76
1 C 2 23.300593 20
2 C 3 11.021624 75
3 Q 1 90.000000 1
4 Q 2 11.735114 7
5 Q 3 10.390820 99
6 S 1 72.235825 113
7 S 2 21.206921 165
8 S 3 14.435460 375
컬럼이 한개이면 on 뒤에 값을 넣고, 다수인 경우 리스트를 이용해서 넣어주면 된다.
apply 메소드
- series, DataFrame에 대한 단순한 집계가 아닌 구체적인 로직을 적용하고 싶을 때 사용
- 각 데이터에 대해 조건 검사 등과 같은 복잡한 처리 가능
- apply 메소드에 우리가 정의한 함수를 넣어주면 된다. (콜백함수를 넣는 것과 비슷)
- 항구별 가족수(sibsp+parch)의 평균을 구하고 싶다면?
- agg 메소드로는 안된다. agg 메소드는 각 컬럼에 대해서만 집계가 가능하다.
예시
def do_apply(x):
return (x["sibsp"] + x["parch"]).mean()
df.groupby("embarked").apply(do_apply)
=>
embarked
C 0.770370
Q 0.455285
S 0.974891
dtype: float64
- apply 경우 apply의 대상이 되는 데이터의 구조에 따라 다르게 처리하거나 축개념이 있다.
- series에 대한 apply
- 축개념이 없고 한 행씩 처리한다.
df["gender"].apply(lambda x: 1 if x == "male" else 0)
=>
0 1
1 0
2 0
3 0
4 1
..
1304 1
1305 0
1306 1
1307 1
1308 1
Name: gender, Length: 1309, dtype: int64
- DataFrame에 대한 apply
- 축개념이 있다.
- axis = 0: 행방향, 컬럼 단위로 처리, 기본값
- axis = 1: 열방향, 행단위로 처리
그래서 축을 잘생각하면서 사용하는 것이 좋다.
- groupby에 대한 apply
- 데이터 프레임이 넘어간다.
def do_apply(x):
display(x)
print("="*50) # 구분선
return x
tmp = df.groupby("embarked").apply(do_apply) # 항구가 3개라 3개로 넘어옴
=>
passengerid survived pclass name gender age sibsp parch ticket fare cabin embarked age2
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38 1 0 PC 17599 71.2833 C85 C 3
9 10 1 2 Nasser, Mrs. Nicholas (Adele Achem) female 14 1 0 237736 30.0708 UNK C 1
19 20 1 3 Masselmani, Mrs. Fatima female 28 0 0 2649 7.2250 UNK C 2
26 27 0 3 Emir, Mr. Farred Chehab male 28 0 0 2631 7.2250 UNK C 2
30 31 0 1 Uruchurtu, Don. Manuel E male 40 0 0 PC 17601 27.7208 UNK C 4
... ... ... ... ... ... ... ... ... ... ... ... ... ...
1295 1296 0 1 Frauenthal, Mr. Isaac Gerald male 43 1 0 17765 27.7208 D40 C 4
1296 1297 0 2 Nourney, Mr. Alfred (Baron von Drachstedt")" male 20 0 0 SC/PARIS 2166 13.8625 D38 C 2
1298 1299 0 1 Widener, Mr. George Dunton male 50 1 1 113503 211.5000 C80 C 5
1305 1306 1 1 Oliva y Ocana, Dona. Fermina female 39 0 0 PC 17758 108.9000 C105 C 3
1308 1309 0 3 Peter, Master. Michael J male 28 1 1 2668 22.3583 UNK C 2
270 rows × 13 columns
==================================================
passengerid survived pclass name gender age sibsp parch ticket fare cabin embarked age2
5 6 0 3 Moran, Mr. James male 28 0 0 330877 8.4583 UNK Q 2
16 17 0 3 Rice, Master. Eugene male 2 4 1 382652 29.1250 UNK Q 0
22 23 1 3 McGowan, Miss. Anna "Annie" female 15 0 0 330923 8.0292 UNK Q 1
28 29 1 3 O'Dwyer, Miss. Ellen "Nellie" female 28 0 0 330959 7.8792 UNK Q 2
32 33 1 3 Glynn, Miss. Mary Agatha female 28 0 0 335677 7.7500 UNK Q 2
... ... ... ... ... ... ... ... ... ... ... ... ... ...
1287 1288 0 3 Colbert, Mr. Patrick male 24 0 0 371109 7.2500 UNK Q 2
1290 1291 0 3 Conlon, Mr. Thomas Henry male 31 0 0 21332 7.7333 UNK Q 3
1299 1300 1 3 Riordan, Miss. Johanna Hannah"" female 28 0 0 334915 7.7208 UNK Q 2
1301 1302 1 3 Naughton, Miss. Hannah female 28 0 0 365237 7.7500 UNK Q 2
1302 1303 1 1 Minahan, Mrs. William Edward (Lillian E Thorpe) female 37 1 0 19928 90.0000 C78 Q 3
123 rows × 13 columns
==================================================
passengerid survived pclass name gender age sibsp parch ticket fare cabin embarked age2
0 1 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.2500 UNK S 2
2 3 1 3 Heikkinen, Miss. Laina female 26 0 0 STON/O2. 3101282 7.9250 UNK S 2
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1000 C123 S 3
4 5 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.0500 UNK S 3
6 7 0 1 McCarthy, Mr. Timothy J male 54 0 0 17463 51.8625 E46 S 5
... ... ... ... ... ... ... ... ... ... ... ... ... ...
1300 1301 1 3 Peacock, Miss. Treasteall female 3 1 1 SOTON/O.Q. 3101315 13.7750 UNK S 0
1303 1304 1 3 Henriksson, Miss. Jenny Lovisa female 28 0 0 347086 7.7750 UNK S 2
1304 1305 0 3 Spector, Mr. Woolf male 28 0 0 A.5. 3236 8.0500 UNK S 2
1306 1307 0 3 Saether, Mr. Simon Sivertsen male 38 0 0 SOTON/O.Q. 3101262 7.2500 UNK S 3
1307 1308 0 3 Ware, Mr. Frederick male 28 0 0 359309 8.0500 UNK S 2
916 rows × 13 columns
==================================================
아규먼트 전달 예시
age_mean = df["age"].mean()
age_mean
=>
29.484339190221544
# 항구별 평균나이와 전체 평균나이의 차이를 집계
def do_apply(x, age_mean):
return x["age"].mean() - age_mean
# apply에 대한 콜백함수에 대한 추가 아규먼트를 전달하고 싶다면
# 키워드 아규먼트 전달방식으로 하면 된다.
df.groupby("embarked").apply(do_apply,age_mean = age_mean)
=>
embarked
C 1.889735
Q -1.248567
S -0.389361
dtype: float64
apply는 자동으로 x가 들어가는데 age_mean은 키워드 아규먼트를 동일하게 하여 함수를 실행한다.
- pandas에서 progress bar 사용하기
from tqdm.auto import tqdm
import time
tqdm.pandas() # 판다스에서 progress_apply 메소드를 사용할 수 있게 된다.
def do_apply(x):
time.sleep(0.01)
return x
tmp = df.progress_apply(do_apply,axis = 1)
=>
100%
1309/1309 [00:00<00:00, 3621.76it/s]
progress bar를 사용하여 데이터의 처리진행도를 알 수 있다.
그래서 진행도를 보고, 화장실이라도 갈 수 있다.
정신없이 전처리하는 거에 대해 배웠는데 매우 흥미로웠다.
전처리를 통해 많은 정보를 도출하는 것이 신기하였다.
'AI 공부 > 파이썬' 카테고리의 다른 글
파이썬 (seaborn) (0) | 2022.08.31 |
---|---|
파이썬 (Matplotlib) (0) | 2022.08.31 |
파이썬 (Pandas를 이용한 EDA) (0) | 2022.08.30 |
파이썬 (Pandas 기초) (0) | 2022.08.30 |
파이썬 (Numpy) (0) | 2022.08.24 |
댓글