Py) 기초 - Pandas(필터링)

Py) 기초 - Pandas(필터링)

파이썬 기반 데이터분석을 위하여 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
## 0 100
## 1 200
## 2 300
## 3 400
## 4 500
## dtype: int64

ser2 = pd.Series(["A", "B", "C", "D", "E"])
ser2
## 0 A
## 1 B
## 2 C
## 3 D
## 4 E
## dtype: object

단일 조건

본격적인 필터링을 알아보기 위해서 필터링의 원리를 알아보자. 다음의 코드를 실행하게되면 결과가 True/False를 원소로 하는 시리즈 객체가 반환된다.

1
2
3
4
5
6
7
ser1 > 200
## 0 False
## 1 False
## 2 True
## 3 True
## 4 True
## dtype: bool

상기 코드는 “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]
## 2 300
## 3 400
## 4 500
## dtype: int64

ser1[ser1 < 200]
## 0 100
## dtype: int64

ser1[ser1 >= 200]
## 1 200
## 2 300
## 3 400
## 4 500
## dtype: int64

ser1[ser1 <= 200]
## 0 100
## 1 200
## dtype: int64

특정 객체 내부의 특정 원소에 접근하는 것 처럼 객체 뒤에 대괄호 안에 필터링 조건을 쓴다. 엄밀히 말하면 필터링 하고자 하는 객체의 원소개수 만큼의 True 또는 False 원소를 대괄호 안에 넣어줘야 한다. 다음의 코드를 보면 조금 더 이해하기 쉽지 않을까 한다.

1
2
3
4
ser1[[True, True, False, False, False]]
## 0 100
## 1 200
## dtype: int64

평균보다 값이 큰 원소만 필터링한다면 다음과 같다.

1
2
3
4
ser1[ser1 > ser1.mean()]
## 3 400
## 4 500
## dtype: int64

특정 원소만 필터링하거나 특정 원소를 제외한 나머지를 필터링 하려면 다음과 같이 쓸 수 있다.

1
2
3
4
5
6
7
8
9
10
ser2[ser2 == "A"]
## 0 A
## dtype: object

ser2[ser2 != "A"]
## 1 B
## 2 C
## 3 D
## 4 E
## dtype: object

최소값 또는 최대값을 제외한 필터링을 하고자 한다면 다음과 같이 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
ser1[ser1 != ser1.max()]
## 0 100
## 1 200
## 2 300
## 3 400
## dtype: int64

ser1[ser1 != ser1.min()]
## 1 200
## 2 300
## 3 400
## 4 500
## dtype: int64

다중 조건

2개 이상의 조건을 사용하여 필터링하는 방법을 알아보자. 여기서는 두 조건을 이어주는 논리연산자와 특정 조건을 감싸는 소괄호의 작성에 주의해야한다. 다음의 코드는 둘 중 하나의 조건(또는 적어도 하나의 조건)을 만족하는 경우로 “OR”조건이라고 하기도 하는 코드와 조건 두 개가 동시에 만족해야하는 “AND”조건의 코드이다. 그 차이점을 잘 보도록 하자.
※ 세로막대(bar)를 입력하기 위해서는 shift키를 누른채로 엔터키 위의 ₩키를 누르면 된다.

1
2
3
4
5
6
7
8
9
10
ser1[(ser1 <= 100) | (ser1 >= 500)]
## 0 100
## 4 500
## dtype: int64

ser1[(ser1 > 100) & (ser1 < 500)]
## 1 200
## 2 300
## 3 400
## dtype: int64

상기 코드를 보다 쉽게 말하자면 첫 번째 코드는 “ser1” 객체의 원소가 100 이하 이거나(or) 500 이상인 원소를 필터링 하는 것이고, 두 번째 코드는 “ser1” 객체의 원소가 100 초과 이면서(and) 500 미만인 원소를 필터링 하는 것이다.

인덱서의 사용

사실상 Pandas 객체는 .iloc[] 또는 .loc[] 인덱서를 사용하여 인덱싱이나 필터링을 하는 것이 정석이나 시리즈 객체의 경우 사용하지 않는 경우가 많다. 앞에 소개한 코드에서 인덱서를 추가해서 필터링 하는 코드를 작성한다면 다음과 같다.

1
2
3
4
ser1.loc[ser1 <= 200]
## 0 100
## 1 200
## dtype: int64

데이터프레임

이제 필터링을 데이터프레임으로 확장해보자. “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
1
2
len(df)
## 53940

단일 조건

이제 특정 변수를 기준으로 필터링을 해보도록 하자. “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
1
2
len(df_sub)
## 36438

데이터프레임 객체를 필터링 할 때는 인덱서 없이도 할 수 있지만 인덱서를 사용하는 것을 권장한다.

시리즈 객체의 필터링 처럼 미만/초과/이상 에 대한 예제 코드는 다음과 같다. 데이터프레임 객체가 2차원 객체이기 때문에 .loc[] 인덱서 안에 쉼표를 써주는 것을 잊지 않도록 한다.

1
2
3
4
5
6
7
8
9
10
11
df_sub2 = df.loc[df["carat"] < 1, ]
len(df_sub2)
## 34880

df_sub3 = df.loc[df["carat"] > 1, ]
len(df_sub3)
## 17052

df_sub4 = df.loc[df["carat"] >= 1, ]
len(df_sub4)
## 19060

특정 원소의 포함 여부와 관련된 필터링을 해보자.

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()
## array(['E', 'I', 'J', 'F', 'G', 'D'], dtype=object)

다중 조건

다중 조건 필터링을 해보자.

1
2
3
4
5
6
7
df_sub7 = df.loc[(df["carat"] < 0.3) | (df["carat"] > 4.8), ]
len(df_sub7)
## 1600

df_sub8 = df.loc[(df["carat"] > 0.3) & (df["carat"] < 4.8), ]
len(df_sub8)
## 49736

필터링하여 “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)
## 12605

df_sub9["color"].unique()
## array(['E', 'J'], dtype=object)

상기 코드는 .isin() 메서드를 사용하면 다음과 같이 보다 빠르고 간결한 코드로 바꿀 수 있으며 필터링에서 많이 활용된다.

1
2
3
df_sub10 = df.loc[df["color"].isin(["E", "J"]), ]
len(df_sub10)
## 12605
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×