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

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

소개

Pandas는 인덱스 위치(index position) 또는 인덱스 레이블(index label)을 사용해 데이터의 부분 집합을 선택할 수 있는 이중 선택 기능을 제공합니다. 이번 글에서는 그중에서도 "사전식(lexicographical) 슬라이싱"을 활용해 데이터의 부분 집합을 선택하는 방법을 소개합니다.

인터넷에는 방대한 양의 데이터셋이 공개되어 있습니다. kaggle.com에서 'movies dataset'을 검색해 보세요. 이 글 역시 캐글(Kaggle)에서 제공하는 영화 데이터셋을 사용합니다.

실습 방법

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

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

2단계. 인덱스를 항상 정렬해 두는 것을 권장합니다. 특히 인덱스가 문자열로 구성된 경우라면 더욱 그렇습니다. 대용량 데이터셋을 다룰 때 인덱스가 정렬되어 있으면 성능 차이를 실감하게 됩니다.

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

걱정하지 마세요. 코드가 영원히 실행되는 것은 아닙니다. 물론 농담이지만, 실제로 인덱스 레이블이 정렬되어 있지 않으면 Pandas는 쿼리와 일치하는 값을 찾기 위해 모든 레이블을 하나씩 처음부터 끝까지 순회해야 합니다. 색인 페이지가 없는 옥스포드 사전을 상상해 보세요. 원하는 단어를 찾으려면 어떻게 해야 할까요? 반면 인덱스가 정렬되어 있다면 원하는 레이블로 즉시 이동할 수 있습니다. Pandas도 마찬가지입니다.

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

# check if the index is sorted or not ?
movies.index.is_monotonic

False

3단계. 확인 결과 인덱스가 정렬되어 있지 않습니다. 이제 'A'로 시작하는 영화들을 선택하려고 시도해 보겠습니다. SQL로 표현하면 다음과 같은 쿼리와 같습니다.

select * from movies where title like 'A%'
movies.loc["Aa":"Bb"]
---------------------------------------------------------------------------
ValueErrorTraceback (most recent call last)
~\anaconda3\lib\site-packages\pandas\core\indexes\base.py in get_slice_bound(self, label, side, kind)
-> raise ValueError("index must be monotonic increasing or decreasing")

ValueError: index must be monotonic increasing or decreasing

During handling of the above exception, another exception occurred:

KeyErrorTraceback (most recent call last)
----> 1 movies.loc["Aa": "Bb"]
...
pandas\_libs\index.pyx in pandas._libs.index.IndexEngine._maybe_get_bool_indexer()
KeyError: 'Aa'

인덱스가 단조 증가(monotonic increasing)하지 않아 KeyError가 발생하며 슬라이싱에 실패했습니다.

4단계. 인덱스를 오름차순으로 정렬한 뒤 동일한 명령을 다시 실행하면, 정렬의 이점을 활용한 사전식 슬라이싱이 가능해집니다.

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

True

5단계. 이제 데이터가 준비되었으므로 본격적으로 사전식 슬라이싱을 수행할 수 있습니다. 영화 제목이 'A'로 시작하는 것부터 'B'로 시작하는 것까지 전부 선택해 보겠습니다.

movies.loc["A":"B"]
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

'Aa'부터 'Bb' 사이의 모든 영화가 정상적으로 추출되었습니다.

주의: 특수문자와 대소문자 처리

사전식 슬라이싱은 유니코드 순서를 따르기 때문에 특수문자나 대소문자가 섞인 제목은 의외의 위치에 배치될 수 있습니다.

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

위 결과처럼 'Æ', 'x', 'e', '[' 등의 문자는 일반적인 알파벳 순서와 다르게 정렬되므로, 슬라이싱 범위를 지정할 때 주의가 필요합니다.

내림차순 정렬 데이터에서의 슬라이싱

데이터가 내림차순으로 정렬되어 있는 상태에서 오름차순 기준의 슬라이싱을 수행하면 어떻게 될까요? 당연하게도 빈 DataFrame이 반환됩니다. 문자 범위의 순서를 반대로 지정해 다시 실행해 보겠습니다.

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

이처럼 인덱스의 정렬 방향에 맞게 슬라이싱 범위를 지정하면, 내림차순으로 정렬된 데이터에서도 원하는 구간을 손쉽게 추출할 수 있습니다.