본문 바로가기
AI 공부/파이썬

파이썬 (Pandas를 이용한 전처리 - 1)

by AI Sonny 2022. 8. 30.
728x90

결측치 다루기

 

- 데이터 파악

 

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를 사용하여 데이터의 처리진행도를 알 수 있다.

 

그래서 진행도를 보고, 화장실이라도 갈 수 있다.

 


정신없이 전처리하는 거에 대해 배웠는데 매우 흥미로웠다.

 

전처리를 통해 많은 정보를 도출하는 것이 신기하였다.

728x90

'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

댓글