소개
이 글에서는 Pandas를 사용해 SQL 스타일의 필터링으로 데이터 분석을 수행하는 방법을 소개합니다. 대부분의 기업 데이터는 데이터베이스에 저장되어 있으며, 이를 조회하고 조작하려면 SQL이 필요합니다. 예를 들어 Oracle, IBM, Microsoft 같은 기업들은 각자 고유한 SQL 구현체를 갖춘 데이터베이스를 제공합니다.
데이터가 항상 CSV 파일 형태로 저장되어 있는 것은 아니기 때문에, 데이터 과학자라면 커리어 과정에서 반드시 SQL을 다루게 됩니다. 저는 개인적으로 Oracle을 선호하는데, 제가 일하는 회사의 데이터 대부분이 Oracle에 저장되어 있기 때문입니다.
시나리오 1
영화 데이터셋에서 아래 조건에 해당하는 모든 영화를 찾는 작업이 주어졌다고 가정해 보겠습니다.
- 영화의 언어는 영어(en) 또는 스페인어(es)여야 합니다.
- 영화의 인기도(popularity)는 500 이상 1000 이하여야 합니다.
- 영화의 상태(status)는 'Released'(개봉)여야 합니다.
- 투표 수(vote_count)는 5,000보다 커야 합니다.
위 시나리오를 SQL로 작성하면 다음과 같습니다.
SELECT
title AS movie_title,
original_language AS movie_language,
popularity AS movie_popularity,
status AS movie_status,
vote_count AS movie_vote_count
FROM movies_data
WHERE original_language IN ('en', 'es')
AND status = 'Released'
AND popularity BETWEEN 500 AND 1000
AND vote_count > 5000;
SQL 쿼리를 확인했으니, 이제 Pandas로 단계별로 동일한 작업을 수행해 보겠습니다. 두 가지 방법을 소개합니다.
방법 1: 불리언 인덱싱(Boolean Indexing)
1단계. movies_data 데이터셋을 DataFrame으로 불러옵니다.
import pandas as pd
movies = pd.read_csv("https://raw.githubusercontent.com/sasankac/TestDataSet/master/movies_data.csv")
2단계. 각 조건을 변수에 할당합니다.
languages = ["en", "es"]
condition_on_languages = movies.original_language.isin(languages)
condition_on_status = movies.status == "Released"
condition_on_popularity = movies.popularity.between(500, 1000)
condition_on_votecount = movies.vote_count > 5000
3단계. 모든 조건(불리언 배열)을 하나로 결합합니다.
final_conditions = (
condition_on_languages
& condition_on_status
& condition_on_popularity
& condition_on_votecount
)
columns = ["title", "original_language", "status", "popularity", "vote_count"]
# 모든 요소를 결합해 최종 결과 추출
movies.loc[final_conditions, columns]
실행 결과는 다음과 같습니다.
| title | original_language | status | popularity | vote_count |
|---|---|---|---|---|
| Interstellar | en | Released | 724.247784 | 10867 |
| Deadpool | en | Released | 514.569956 | 10995 |
방법 2: .query() 메서드
.query() 메서드는 SQL의 WHERE 절 스타일로 데이터를 필터링할 수 있는 방법입니다. 조건을 문자열 형태로 전달하며, 단 열 이름에 공백이 없어야 합니다.
열 이름에 공백이 포함되어 있다면 파이썬의 replace() 함수를 사용해 밑줄(_)로 변경하세요.
경험상 큰 규모의 DataFrame에 query() 메서드를 적용하면 앞서 소개한 방법보다 더 빠르게 동작합니다.
먼저 데이터를 로드합니다.
import pandas as pd
movies = pd.read_csv("https://raw.githubusercontent.com/sasankac/TestDataSet/master/movies_data.csv")
4단계. 쿼리 문자열을 작성하고 메서드를 실행합니다.
주의: .query() 메서드는 여러 줄에 걸친 삼중 따옴표(triple quoted) 문자열과 함께 사용할 수 없습니다.
final_conditions = (
"original_language in ['en','es']"
"and status == 'Released' "
"and popularity > 500 "
"and popularity < 1000"
"and vote_count > 5000"
)
final_result = movies.query(final_conditions)
final_result
실행 결과:
| budget | id | original_language | original_title | popularity | release_date | revenue | runtime | status | |
|---|---|---|---|---|---|---|---|---|---|
| 95 | 165000000 | 157336 | en | Interstellar | 724.247784 | 5/11/2014 | 675120017 | 169.0 | Released |
| 788 | 58000000 | 293660 | en | Deadpool | 514.569956 | 9/02/2016 | 783112979 | 108.0 | Released |
@ 기호로 파이썬 변수 참조하기
여기서 한 단계 더 나아가 보겠습니다. 실제 코딩에서는 'in' 절에서 확인해야 할 값이 여러 개인 경우가 많은데, 위와 같은 문법은 그다지 이상적이지 않습니다. 이럴 때 @ 기호를 사용하면 쿼리 문자열 안에서 파이썬 변수를 직접 참조할 수 있습니다.
값들을 프로그래밍 방식으로 파이썬 리스트로 생성한 뒤 @와 함께 사용할 수도 있습니다.
movie_languages = ['en', 'es']
final_conditions = (
"original_language in @movie_languages "
"and status == 'Released' "
"and popularity > 500 "
"and popularity < 1000"
"and vote_count > 5000"
)
final_result = movies.query(final_conditions)
final_result
결과는 앞선 예제와 동일하게 Interstellar와 Deadpool 두 영화가 반환됩니다.
마무리
정리하면, Pandas에서 SQL 스타일의 데이터 필터링은 불리언 인덱싱과 .query() 메서드 두 가지 방식으로 수행할 수 있습니다. 조건이 복잡하고 단계별로 검증하고 싶다면 불리언 인덱싱이, SQL에 익숙하고 코드를 간결하게 유지하고 싶다면 .query() 메서드가 적합합니다. 특히 대용량 DataFrame에서는 .query() 메서드가 더 나은 성능을 보이므로, 상황에 맞게 두 방법을 활용해 보시기 바랍니다.