본문으로 건너뛰기
KDNugget조회 2

초보자도 쉽게 따라 하는 느린 Python 코드 가속화 방법 5가지

Python의 내장 함수, 효율적인 데이터 구조, 그리고 NumPy/Pandas 벡터화를 활용하여 초보자도 코드 실행 속도를 획기적으로 개선하는 실전 가이드를 제공합니다.

섹션별 상세

최적화 전 time 모듈이나 cProfile을 사용하여 실제 병목 지점을 정확히 측정해야 한다. time.perf_counter()를 활용해 각 코드 블록의 실행 시간을 측정함으로써 짐작이 아닌 데이터에 기반한 최적화 대상을 선정한다. 필터링 작업이 리포트 생성보다 느리다는 것을 수치로 확인하면 헛된 노력을 줄일 수 있다. 이는 한정된 자원을 가장 효과적인 곳에 집중하게 해준다.
python
import time

def load_records():
    return list(range(100_000))

def filter_records(records):
    return [r for r in records if r % 2 == 0]

start = time.perf_counter()
records = load_records()
print(f"Load : {time.perf_counter() - start:.4f}s")

start = time.perf_counter()
filtered = filter_records(records)
print(f"Filter : {time.perf_counter() - start:.4f}s")

time.perf_counter()를 사용하여 각 코드 블록의 실행 시간을 정밀하게 측정하는 예시

Python의 내장 함수는 C 언어로 구현되어 있어 순수 Python 루프보다 훨씬 빠른 성능을 제공한다. sum(), map(), sorted()와 같은 함수를 사용하면 수동 루프 대비 약 6배 이상의 속도 향상을 기대할 수 있다. 예를 들어 100만 개의 숫자를 더할 때 수동 루프는 0.11초가 걸리지만 sum()은 0.01초 만에 완료된다. 따라서 일반적인 로직을 직접 구현하기 전 표준 라이브러리 존재 여부를 확인하는 것이 중요하다.
python
import time
numbers = list(range(1_000_000))

# Manual loop
start = time.perf_counter()
total = 0
for n in numbers:
    total += n
print(f"Manual loop : {time.perf_counter() - start:.4f}s")

# Built-in sum()
start = time.perf_counter()
total = sum(numbers)
print(f"Built-in : {time.perf_counter() - start:.4f}s")

수동 루프와 내장 sum() 함수의 실행 속도 차이를 비교하는 예시

루프 내부에서 매번 동일한 결과를 내는 비싼 연산을 수행하는 것은 전형적인 성능 저하의 원인이다. 리스트를 세트로 변환하거나 정규표현식을 컴파일하는 작업 등을 루프 외부로 이동시키면 반복되는 비용을 1회로 줄일 수 있다. 실제 사례에서 리스트 멤버십 체크를 세트 체크로 바꾸고 변환 과정을 루프 밖으로 뺐을 때 실행 시간이 0.37초에서 0.001초로 단축됐다. 이는 알고리즘의 시간 복잡도를 직접적으로 개선하는 효과가 있다.
python
# Slow: list membership check inside loop
for code in incoming:
    if code in approved: # O(n) slow
        valid.append(code)

# Fast: convert to set outside loop
approved_set = set(approved)
for code in incoming:
    if code in approved_set: # O(1) fast
        valid.append(code)

반복적인 리스트 검색을 세트 검색으로 최적화하여 루프 속도를 높이는 예시

데이터의 특성에 맞는 구조를 선택하는 것만으로도 검색 속도를 비약적으로 높일 수 있다. 리스트는 요소가 늘어날수록 검색 시간이 선형적으로 증가하지만, 세트나 딕셔너리는 해싱을 통해 상수 시간에 검색을 수행한다. 10만 개의 고객 ID 중 주문자를 찾는 테스트에서 리스트는 16.7초가 소요된 반면 세트는 0.009초 만에 작업을 끝냈다. 대규모 데이터셋에서 멤버십 확인이 잦다면 세트 사용이 필수적이다.
수치 연산이나 대량의 데이터 프레임 처리 시에는 Python 루프 대신 NumPy나 Pandas의 벡터화 연산을 사용해야 한다. 벡터화는 전체 배열에 연산을 한 번에 적용하여 내부적으로 최적화된 C 코드를 실행하므로 Python의 오버헤드를 제거한다. 50만 개의 가격 데이터를 처리할 때 Python 루프는 1초가 걸리지만 NumPy는 0.01초, Pandas는 0.003초로 최대 수백 배 빠르다. 특히 Pandas의 iterrows()는 가급적 피하고 컬럼 단위 연산을 지향해야 한다.
python
import numpy as np
prices_array = np.array(prices)

# NumPy vectorization
start = time.perf_counter()
discounted = np.round(prices_array * (1 - discount_rate), 2)
print(f"NumPy : {time.perf_counter() - start:.4f}s")

NumPy 배열 연산을 통해 루프 없이 대량의 수치 데이터를 한 번에 처리하는 예시

용어 해설

프로파일링(Profiling)
코드의 실행 시간과 자원 사용량을 측정하여 성능 병목 지점을 찾는 과정이다. cProfile 같은 도구를 사용해 어떤 함수가 가장 많은 시간을 소비하는지 파악한다. 이를 통해 막연한 추측이 아닌 실제 데이터에 기반한 최적화가 가능하다.
벡터화(Vectorization)
루프를 사용하는 대신 배열 전체에 연산을 한 번에 적용하는 기법이다. 내부적으로 최적화된 C 코드를 호출하여 Python의 반복문 오버헤드를 제거한다. NumPy와 Pandas의 핵심 성능 비결이며 대규모 수치 계산에 필수적이다.
시간 복잡도(Time Complexity)
알고리즘이 문제를 해결하는 데 걸리는 시간을 입력 데이터 크기에 따른 함수로 표현한 것이다. 리스트 검색은 O(n)이지만 세트 검색은 O(1)로 데이터가 많아질수록 성능 차이가 극명해진다. 효율적인 데이터 구조 선택의 이론적 근거가 된다.
해싱(Hashing)
가변 길이의 데이터를 고정된 크기의 고유한 값으로 변환하는 과정이다. 세트(Set)나 딕셔너리(Dict)는 이 해시 값을 인덱스로 사용하여 데이터 존재 여부를 즉각 확인한다. 리스트처럼 처음부터 끝까지 훑지 않아도 되므로 검색 속도가 매우 빠르다.

기술

  • Python
  • NumPy
  • Pandas
  • cProfile

활용 사례

  • 데이터 전처리 가속화
  • 대규모 리스트 필터링
  • 수치 계산 최적화
AI 분석 전체 내용 보기

AI 요약 · 북마크 · 개인 피드 설정 — 무료

출처 · 인용 안내

원문 발행 2026. 03. 23.수집 2026. 03. 23.출처 타입 RSS

인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.