Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬 Pandas 사전식(lexicographical) 슬라이싱으로 데이터 부분 집합 선택하기

소개

Pandas는 인덱스 위치(Index position) 또는 인덱스 레이블(Index label) 두 가지 방식으로 데이터의 부분 집합을 선택할 수 있는 강력한 기능을 제공합니다. 이 글에서는 그중에서도 사전식 슬라이싱(lexicographical slicing)을 활용해 데이터의 일부를 선택하는 방법을 소개합니다.

데이터셋을 찾고 있다면 Kaggle(kaggle.com)에서 'movies dataset'을 검색해 보세요. 이 글에서는 Kaggle의 영화 데이터셋을 예제로 사용합니다.

실습 방법

먼저 예제에 필요한 컬럼만 골라서 영화 데이터셋을 불러옵니다.

import pandas as pd
import numpy as np

movies = pd.read_csv(
    "https://raw.githubusercontent.com/sasankac/TestDataSet/master/movies_data.csv",
    index_col="title",
    usecols=["title", "budget", "vote_average", "vote_count"]
)
movies.sample(n=5)

샘플 데이터는 아래와 같습니다.

titlebudgetvote_averagevote_count
Little Voice06.661
Grown Ups 2800000005.81155
The Best Years of Our Lives21000007.6143
Tusk28000005.1366
Operation Chromite05.829

인덱스 정렬은 왜 중요할까?

인덱스가 문자열로 구성된 경우에는 반드시 정렬(sort)을 해두는 것을 권장합니다. 대용량 데이터셋을 다룰 때 인덱스가 정렬되어 있으면 성능 차이를 체감할 수 있습니다.

인덱스를 정렬하지 않으면 어떻게 될까?

코드가 영원히 실행되는 건 아니지만(물론 농담입니다), 인덱스 레이블이 정렬되어 있지 않으면 Pandas는 쿼리와 일치하는 값을 찾기 위해 모든 레이블을 하나씩 순회해야 합니다. 색인 페이지 없는 옥스포드 사전을 상상해 보세요. 원하는 단어를 찾으려면 처음부터 한 장씩 넘겨야 할 겁니다. 반면 정렬된 인덱스가 있으면 원하는 위치로 바로 점프할 수 있듯이, Pandas도 마찬가지로 빠르게 탐색할 수 있습니다.

먼저 현재 인덱스가 정렬되어 있는지 확인해 보겠습니다.

# 인덱스가 정렬되어 있는지 확인
movies.index.is_monotonic
False

결과가 False이므로 인덱스가 정렬되어 있지 않다는 것을 알 수 있습니다.

정렬되지 않은 상태에서 슬라이싱 시도

이제 'A'로 시작하는 영화 제목만 선택해 보려 합니다. SQL로 표현하면 다음과 같습니다.

select * from movies where title like 'A%'

Pandas에서는 다음과 같이 작성할 수 있습니다.

movies.loc["Aa":"Bb"]

그런데 실행하면 아래와 같은 에러가 발생합니다.

ValueError: index must be monotonic increasing or decreasing
KeyError: 'Aa'

즉, 인덱스가 단조 증가(monotonic increasing)하거나 단조 감소(monotonic decreasing) 상태여야만 레이블 기반 슬라이싱이 가능하다는 의미입니다.

인덱스 정렬 후 사전식 슬라이싱

인덱스를 오름차순으로 정렬한 뒤 동일한 명령을 다시 실행하면, 정렬의 이점을 살린 사전식 슬라이싱을 사용할 수 있습니다.

movies = movies.sort_index()
movies.index.is_monotonic
True

이제 데이터가 준비되었습니다. 'A'로 시작하는 영화 제목부터 'B'로 시작하는 제목까지 모두 선택해 보겠습니다.

movies.loc["A":"C"]
titlebudgetvote_averagevote_count
Abandon250000004.645
Abandoned05.827
Abduction350000005.6961
Aberdeen07.06
About Last Night125000006.0210
............
Battle for the Planet of the Apes17000005.5215
Battle of the Year200000005.988
Battle: Los Angeles700000005.51448
Battlefield Earth440000003.0255
Battleship2090000005.52114

292 rows × 3 columns

내림차순 정렬된 경우 주의점

아래 표처럼 특수문자나 소문자가 포함된 제목들은 유니코드 순서상 앞쪽에 배치됩니다.

titlebudgetvote_averagevote_count
Æon Flux620000005.4703
xXx: State of the Union600000004.7549
xXx700000005.81424
eXistenZ150000006.7475
[REC]²56000006.4489

만약 데이터가 내림차순으로 정렬되어 있는데 오름차순 범위(예: "Aa" → "Bb")로 슬라이싱하면 결과가 비어 있는(empty) DataFrame이 반환됩니다. 이 경우에는 범위의 시작과 끝을 반대로 지정해서 실행하면 됩니다.

movies.loc["Bb":"Aa"]
titlebudgetvote_averagevote_count
B-Girl05.57
Ayurveda: Art of Being3000005.53
Away We Go170000006.7189
Awake860000006.3395
Avengers: Age of Ultron2800000007.36767
............
About Last Night125000006.0210
Aberdeen07.06
Abduction350000005.6961
Abandoned05.827
Abandon250000004.645

228 rows × 3 columns

정리

  • Pandas의 .loc[] 슬라이싱으로 문자열 인덱스를 사전식(lexicographical) 범위 조회할 수 있습니다.
  • 슬라이싱 전에 반드시 index.is_monotonic으로 정렬 여부를 확인하세요.
  • 정렬되지 않은 인덱스로 슬라이싱하면 ValueError: index must be monotonic increasing or decreasing 에러가 발생합니다.
  • sort_index()로 인덱스를 정렬하면 대용량 데이터에서도 빠른 조회가 가능합니다.
  • 내림차순 정렬된 데이터는 범위의 시작과 끝을 반대로 지정해야 올바른 결과를 얻을 수 있습니다.