파이썬 기반 데이터분석을 위하여 Pandas 라이브러리 객체를 필터링하는 방법을 알아보고자 한다.
※ 본 내용에서 사용하는 diamonds.csv 파일은 별도로 다운로드 받아야 한다. ※ diamonds.csv 다운받기 [클릭]
개요 Pandas 객체를 필터링 하는 방법을 알아보고자 한다. 시리즈(Series)객체와 데이터프레임(DataFrame)객체의 필터링에 대해 다루게 되는데 기본적으로 시리즈 객체를 필터링할 수 있어야 데이터프레임 객체 또한 쉽게 다룰 수 있다.
시리즈(Series) 다음의 시리즈 객체를 준비하자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ser1 = pd.Series([100 , 200 , 300 , 400 , 500 ]) ser1 ser2 = pd.Series(["A" , "B" , "C" , "D" , "E" ]) ser2
단일 조건 본격적인 필터링을 알아보기 위해서 필터링의 원리를 알아보자. 다음의 코드를 실행하게되면 결과가 True
/False
를 원소로 하는 시리즈 객체가 반환된다.
상기 코드는 “ser1” 객체의 각 원소가 200 초과인지 아닌지 검사하는 코드라고 할 수 있겠다. “ser1” 객체가 Pandas 객체가 아닌 리스트 객체였다면 상기 작업은 반복문을 사용했어야 될지도 모른다. 그런데 Pandas 객체이기 때문에 아주 간결한 코드로 상기와 같은 결과를 얻을 수 있고 이를 필터링에 활용할 수 있다.
초과/미만/이상/이하 연산은 다음과 같이 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ser1[ser1 > 200 ] ser1[ser1 < 200 ] ser1[ser1 >= 200 ] ser1[ser1 <= 200 ]
특정 객체 내부의 특정 원소에 접근하는 것 처럼 객체 뒤에 대괄호 안에 필터링 조건을 쓴다. 엄밀히 말하면 필터링 하고자 하는 객체의 원소개수 만큼의 True
또는 False
원소를 대괄호 안에 넣어줘야 한다. 다음의 코드를 보면 조금 더 이해하기 쉽지 않을까 한다.
1 2 3 4 ser1[[True , True , False , False , False ]]
평균보다 값이 큰 원소만 필터링한다면 다음과 같다.
1 2 3 4 ser1[ser1 > ser1.mean()]
특정 원소만 필터링하거나 특정 원소를 제외한 나머지를 필터링 하려면 다음과 같이 쓸 수 있다.
1 2 3 4 5 6 7 8 9 10 ser2[ser2 == "A" ] ser2[ser2 != "A" ]
최소값 또는 최대값을 제외한 필터링을 하고자 한다면 다음과 같이 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 ser1[ser1 != ser1.max()] ser1[ser1 != ser1.min()]
다중 조건 2개 이상의 조건을 사용하여 필터링하는 방법을 알아보자. 여기서는 두 조건을 이어주는 논리연산자와 특정 조건을 감싸는 소괄호의 작성에 주의해야한다. 다음의 코드는 둘 중 하나의 조건(또는 적어도 하나의 조건)을 만족하는 경우로 “OR”조건이라고 하기도 하는 코드와 조건 두 개가 동시에 만족해야하는 “AND”조건의 코드이다. 그 차이점을 잘 보도록 하자. ※ 세로막대(bar)를 입력하기 위해서는 shift키를 누른채로 엔터키 위의 ₩키를 누르면 된다.
1 2 3 4 5 6 7 8 9 10 ser1[(ser1 <= 100 ) | (ser1 >= 500 )] ser1[(ser1 > 100 ) & (ser1 < 500 )]
상기 코드를 보다 쉽게 말하자면 첫 번째 코드는 “ser1” 객체의 원소가 100 이하 이거나(or)
500 이상인 원소를 필터링 하는 것이고, 두 번째 코드는 “ser1” 객체의 원소가 100 초과 이면서(and)
500 미만인 원소를 필터링 하는 것이다.
인덱서의 사용 사실상 Pandas 객체는 .iloc[]
또는 .loc[]
인덱서를 사용하여 인덱싱이나 필터링을 하는 것이 정석이나 시리즈 객체의 경우 사용하지 않는 경우가 많다. 앞에 소개한 코드에서 인덱서를 추가해서 필터링 하는 코드를 작성한다면 다음과 같다.
1 2 3 4 ser1.loc[ser1 <= 200 ]
데이터프레임 이제 필터링을 데이터프레임으로 확장해보자. “diamonds.csv” 파일을 읽어와서 “df” 객체에 저장하자. ※ 파일 다운로드 링크는 포스팅 최상단 참고. ※ 인덱서를 사용하지 않는 필터링 코드는 다루지 않음
1 2 df = pd.read_csv("diamonds.csv" ) df.head()
carat
cut
color
clarity
depth
table
price
x
y
z
0
0.23
Ideal
E
SI2
61.5
55.0
326
3.95
3.98
2.43
1
0.21
Premium
E
SI1
59.8
61.0
326
3.89
3.84
2.31
2
0.23
Good
E
VS1
56.9
65.0
327
4.05
4.07
2.31
3
0.29
Premium
I
VS2
62.4
58.0
334
4.20
4.23
2.63
4
0.31
Good
J
SI2
63.3
58.0
335
4.34
4.35
2.75
단일 조건 이제 특정 변수를 기준으로 필터링을 해보도록 하자. “carat” 변수가 1 이하인 행을 필터링 하자.
1 2 df_sub1 = df.loc[df["carat" ] <= 1 , ] df_sub1.tail()
carat
cut
color
clarity
depth
table
price
x
y
z
53935
0.72
Ideal
D
SI1
60.8
57.0
2757
5.75
5.76
3.50
53936
0.72
Good
D
SI1
63.1
55.0
2757
5.69
5.75
3.61
53937
0.70
Very Good
D
SI1
62.8
60.0
2757
5.66
5.68
3.56
53938
0.86
Premium
H
SI2
61.0
58.0
2757
6.15
6.12
3.74
53939
0.75
Ideal
D
SI2
62.2
55.0
2757
5.83
5.87
3.64
데이터프레임 객체를 필터링 할 때는 인덱서 없이도 할 수 있지만 인덱서를 사용하는 것을 권장한다.
시리즈 객체의 필터링 처럼 미만/초과/이상 에 대한 예제 코드는 다음과 같다. 데이터프레임 객체가 2차원 객체이기 때문에 .loc[]
인덱서 안에 쉼표를 써주는 것을 잊지 않도록 한다.
1 2 3 4 5 6 7 8 9 10 11 df_sub2 = df.loc[df["carat" ] < 1 , ] len(df_sub2) df_sub3 = df.loc[df["carat" ] > 1 , ] len(df_sub3) df_sub4 = df.loc[df["carat" ] >= 1 , ] len(df_sub4)
특정 원소의 포함 여부와 관련된 필터링을 해보자.
1 2 df_sub5 = df.loc[df["color" ] == "H" , ] df_sub5.head()
carat
cut
color
clarity
depth
table
price
x
y
z
7
0.26
Very Good
H
SI1
61.9
55.0
337
4.07
4.11
2.53
9
0.23
Very Good
H
VS1
59.4
61.0
338
4.00
4.05
2.39
22
0.23
Very Good
H
VS1
61.0
57.0
353
3.94
3.96
2.41
37
0.31
Good
H
SI1
64.0
54.0
402
4.29
4.31
2.75
44
0.32
Good
H
SI2
63.1
56.0
403
4.34
4.37
2.75
1 2 df_sub6 = df.loc[df["color" ] != "H" , ] df_sub6.head()
carat
cut
color
clarity
depth
table
price
x
y
z
0
0.23
Ideal
E
SI2
61.5
55.0
326
3.95
3.98
2.43
1
0.21
Premium
E
SI1
59.8
61.0
326
3.89
3.84
2.31
2
0.23
Good
E
VS1
56.9
65.0
327
4.05
4.07
2.31
3
0.29
Premium
I
VS2
62.4
58.0
334
4.20
4.23
2.63
4
0.31
Good
J
SI2
63.3
58.0
335
4.34
4.35
2.75
1 2 df_sub6["color" ].unique()
다중 조건 다중 조건 필터링을 해보자.
1 2 3 4 5 6 7 df_sub7 = df.loc[(df["carat" ] < 0.3 ) | (df["carat" ] > 4.8 ), ] len(df_sub7) df_sub8 = df.loc[(df["carat" ] > 0.3 ) & (df["carat" ] < 4.8 ), ] len(df_sub8)
필터링하여 “df_sub7” 객체를 만드는 첫 번째 코드를 해석하자면 “df” 객체의 “carat” 변수의 값이 0.3보다 작거나 “df”객체의 “carat” 변수의 값이 4.8보다 큰 행을 필터링 한다는 것이고, 두 번째 코드를 해석하면 “df” 객체의 “carat” 변수의 값이 0.3보다 크면서 “df” 객체의 “carat” 변수의 값이 4.8보다 작은 행을 필터링 한다는 뜻이다.
“df”객체의 “color”변수의 원소가 “E” 또는 “J”인 것을 필터링 하려면 다음과 같다.
1 2 3 4 5 6 df_sub9 = df.loc[(df["color" ] == "E" ) | (df["color" ] == "J" ), ] len(df_sub9) df_sub9["color" ].unique()
상기 코드는 .isin()
메서드를 사용하면 다음과 같이 보다 빠르고 간결한 코드로 바꿀 수 있으며 필터링에서 많이 활용된다.
1 2 3 df_sub10 = df.loc[df["color" ].isin(["E" , "J" ]), ] len(df_sub10)