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

Python에서 최댓값·최솟값 찾기: min(), max(), heapq, pandas DataFrame 활용법

이 글은 Python으로 데이터 집합에서 가장 큰 값이나 가장 작은 값을 찾고 싶은 개발자를 위해 준비했습니다. 단순히 하나의 값만 필요한 경우부터 여러 개의 상위·하위 항목이 필요한 경우, 그리고 DataFrame을 다룰 때까지 상황별로 사용할 수 있는 방법들을 예제와 함께 소개하고, 마지막에 어떤 방법이 가장 효율적인지 정리해 드리겠습니다.

방법 1 – 리스트 슬라이싱(Slice) 접근

만약 단순히 가장 작은 값 하나 또는 가장 큰 값 하나(N=1)만 찾고 있다면, min()max()를 사용하는 것이 가장 빠릅니다.

먼저 임의의 정수 리스트를 생성해 보겠습니다.

import random

# 1~9 범위의 정수로 무작위 리스트 생성
random_list = random.sample(range(1, 10), 9)
random_list

실행 결과

[2, 4, 5, 1, 7, 9, 6, 8, 3]

가장 작은 값과 가장 큰 값 찾기 (N=1)

# 가장 작은 숫자 찾기 (N=1)
min(random_list)

실행 결과

1
# 가장 큰 숫자 찾기 (N=1)
max(random_list)

실행 결과

9

가장 작은 값 3개와 가장 큰 값 3개 찾기 (N=3)

반대로 N이 컬렉션 전체 크기와 비슷한 수준이라면, 먼저 정렬한 뒤 슬라이스로 N개만 잘라내는 것이 일반적으로 더 빠릅니다.

# 슬라이싱으로 가장 작은 값 3개 구하기 (N=3)
sorted(random_list)[:3]

실행 결과

[1, 2, 3]
# 슬라이싱으로 가장 큰 값 3개 구하기 (N=3)
sorted(random_list)[-3:]

실행 결과

[7, 8, 9]

방법 2 – heapq 모듈 활용

heapq 모듈에는 nlargest()nsmallest()라는 두 함수가 있으며, 이를 사용하면 가장 큰 N개 또는 가장 작은 N개의 항목을 손쉽게 구할 수 있습니다.

import heapq
import random

random_list = random.sample(range(1, 10), 9)

# 가장 작은 항목 3개 (N=3)
heapq.nsmallest(3, random_list)

실행 결과

[1, 2, 3]
# 가장 큰 항목 3개 (N=3)
heapq.nlargest(3, random_list)

실행 결과

[9, 8, 7]

조금 더 복잡한 데이터를 다룰 때는 key 매개변수를 활용할 수 있습니다.

import heapq

grandslams = [
    {'name': 'Roger Federer', 'titles': 20},
    {'name': 'Rafael Nadal', 'titles': 19},
    {'name': 'Novak Djokovic', 'titles': 17},
    {'name': 'Andy Murray', 'titles': 3},
]

# 타이틀 수가 적은 선수 3명 (N=3)
less = heapq.nsmallest(3, grandslams, key=lambda s: s['titles'])
less

실행 결과

[{'name': 'Andy Murray', 'titles': 3},
 {'name': 'Novak Djokovic', 'titles': 17},
 {'name': 'Rafael Nadal', 'titles': 19}]
# 타이틀 수가 많은 선수 3명 (N=3)
more = heapq.nlargest(3, grandslams, key=lambda s: s['titles'])
more

실행 결과

[{'name': 'Roger Federer', 'titles': 20},
 {'name': 'Rafael Nadal', 'titles': 19},
 {'name': 'Novak Djokovic', 'titles': 17}]

DataFrame에서 가장 큰 값과 작은 값 N개 찾기

현실의 데이터 세상은 CSV 파일로 가득합니다. 따라서 Python 개발을 하다 보면 언젠가는 CSV와 DataFrame을 다루게 될 가능성이 매우 높습니다. 여기서는 DataFrame에서 가장 큰 값 또는 작은 값 N개를 찾는 두 가지 방법을 소개합니다.

첫 번째 방법은 sort_values() 메서드로 값을 정렬한 뒤, head() 메서드로 원하는 개수만큼 가져오는 것입니다.

import pandas as pd
import io

# 샘플 데이터 정의
data = '''
player,titles
Djokovic,17
Nadal,19
Federer,20
Murray,3
'''
throwaway_storage = io.StringIO(data)
df = pd.read_csv(throwaway_storage, index_col='player')
# 가장 작은 값 3개 (N=3)
df.sort_values('titles').head(3)

실행 결과

          titles
player          
Murray         3
Djokovic      17
Nadal         19
# 가장 큰 값 3개 (N=3)
df.sort_values('titles', ascending=False).head(3)

실행 결과

          titles
player          
Federer       20
Nadal         19
Djokovic      17

행을 정렬한 후 .head()를 호출하는 대신, DataFrame에서 직접 제공하는 .nsmallest().nlargest() 메서드를 호출할 수도 있습니다. 코드가 더 간결하고 의도도 명확하게 드러납니다.

df.nsmallest(3, columns='titles')

실행 결과

          titles
player          
Murray         3
Djokovic      17
Nadal         19
df.nlargest(3, columns='titles')

실행 결과

          titles
player          
Federer       20
Nadal         19
Djokovic      17

마무리: 어떤 방법을 선택해야 할까?

찾으려는 항목의 개수가 전체 데이터에 비해 상대적으로 적다면 nlargest()nsmallest() 함수가 가장 적합합니다.

단순히 가장 작은 값 하나 또는 가장 큰 값 하나(N=1)만 필요하다면 min()max()를 사용하는 것이 더 빠릅니다.

마찬가지로 N이 컬렉션 전체 크기와 비슷하다면, 먼저 정렬한 뒤 슬라이스를 잘라내는 것이 일반적으로 더 빠릅니다.

결론적으로 Python의 nlargest()nsmallest() 구현은 상황에 맞게 동작 방식을 유연하게 조정하며, 이러한 최적화 중 일부를 자동으로 수행해 줍니다. 따라서 특별한 이유가 없다면 heapq의 함수들을 우선 사용하고, 성능이 중요한 경우에는 위의 가이드라인에 따라 상황에 맞는 방법을 선택하는 것이 좋습니다.