Python 복잡한 리스트 필터링: filter
vs 리스트 컴프리헨션, 무엇이 더 나을까?
데이터 전처리나 리스트에서 특정 조건에 맞는 요소를 추출하는 작업은 Python에서 자주 필요한 작업 중 하나입니다. 이런 경우, filter()
함수와 리스트 컴프리헨션(List Comprehension)을 사용할 수 있습니다. 하지만 둘 중 어떤 방법이 더 적합할까요? 이번 글에서는 두 방법을 비교하며 실제 데이터 처리에서 유용한 코드 예제와 함께 이해하기 쉽게 설명하겠습니다.
1. filter
와 리스트 컴프리헨션의 기본 개념
filter()
함수
filter()
함수는 조건에 맞는 요소만 걸러내는 내장 함수입니다.- 첫 번째 인자로 필터링 조건을 정의하는 함수, 두 번째 인자로 필터링 대상 데이터를 받습니다.
- 결과는 이터레이터 형태로 반환됩니다.
nums = [1, 2, 3, 4, 5]
filtered = filter(lambda x: x % 2 == 0, nums) # 짝수만 필터링
print(list(filtered)) # [2, 4]
리스트 컴프리헨션
- 리스트 컴프리헨션은 리스트를 생성하면서 특정 조건에 맞는 요소만 포함할 수 있습니다.
- 더 간결한 구문으로 조건을 표현할 수 있습니다.
nums = [1, 2, 3, 4, 5]
filtered = [x for x in nums if x % 2 == 0] # 짝수만 필터링
print(filtered) # [2, 4]
2. 실제 데이터 처리에서 두 방법 비교
상황: 딥러닝 데이터 전처리
문제: 딥러닝 모델을 학습시키기 전에, 결측값이 있는 데이터를 제거하고, 입력 크기를 기준으로 데이터 필터링을 진행해야 합니다.
filter
사용
# 데이터 예시
data = [
{"id": 1, "input": [0.1, 0.2], "label": 1},
{"id": 2, "input": [0.3, None], "label": 0},
{"id": 3, "input": [0.5, 0.7], "label": 1},
]
# 결측값이 없는 데이터만 필터링
def is_valid(sample):
return None not in sample["input"]
filtered_data = filter(is_valid, data)
print(list(filtered_data))
결과
[{'id': 1, 'input': [0.1, 0.2], 'label': 1}, {'id': 3, 'input': [0.5, 0.7], 'label': 1}]
리스트 컴프리헨션 사용
# 결측값이 없는 데이터만 필터링
filtered_data = [sample for sample in data if None not in sample["input"]]
print(filtered_data)
결과
[{'id': 1, 'input': [0.1, 0.2], 'label': 1}, {'id': 3, 'input': [0.5, 0.7], 'label': 1}]
비교
- 가독성: 리스트 컴프리헨션은 코드가 더 짧고 명확합니다.
- 함수 재사용성:
filter
는is_valid
와 같은 함수를 정의하여 조건을 독립적으로 관리할 수 있어 재사용성이 높습니다.
3. 성능 비교: 언제 무엇을 써야 할까?
리스트 크기가 클 때
filter
와 리스트 컴프리헨션 모두 큰 리스트를 처리할 수 있지만, filter
는 지연 평가(Lazy Evaluation)를 사용해 조건에 맞는 요소를 하나씩 처리합니다. 반면, 리스트 컴프리헨션은 한 번에 모든 데이터를 처리하여 새 리스트를 생성합니다.
예제: 메모리 효율 테스트
import sys
nums = range(1, 1000000) # 100만 개의 숫자
filtered_with_filter = filter(lambda x: x % 2 == 0, nums)
filtered_with_comprehension = [x for x in nums if x % 2 == 0]
print(sys.getsizeof(filtered_with_filter)) # 매우 작은 크기 (이터레이터)
print(sys.getsizeof(filtered_with_comprehension)) # 메모리 크기가 커짐 (리스트)
결과
112
84488
메모리 효율이 중요한 경우
filter
는 이터레이터를 반환하기 때문에 메모리를 덜 사용합니다.- 리스트 컴프리헨션은 새로운 리스트를 생성하므로 더 많은 메모리를 사용합니다.
4. 복잡한 조건 필터링: 다중 조건 적용하기
상황: 딥러닝 라벨 기준으로 데이터 필터링
라벨이 1이고, 입력 데이터의 길이가 2 이상인 샘플만 필터링합니다.
filter
사용
# 다중 조건을 적용한 필터링 함수
def is_valid(sample):
return sample["label"] == 1 and len(sample["input"]) >= 2
filtered_data = filter(is_valid, data)
print(list(filtered_data))
결과
[{'id': 1, 'input': [0.1, 0.2], 'label': 1}, {'id': 3, 'input': [0.5, 0.7], 'label': 1}]
리스트 컴프리헨션 사용
filtered_data = [
sample for sample in data
if sample["label"] == 1 and len(sample["input"]) >= 2
]
print(filtered_data)
결과
[{'id': 1, 'input': [0.1, 0.2], 'label': 1}, {'id': 3, 'input': [0.5, 0.7], 'label': 1}]
비교
- 가독성: 리스트 컴프리헨션은 조건을 함수로 분리하지 않아 간단한 조건에서는 더 직관적입니다.
- 유연성:
filter
는 조건을 함수로 정의하므로 조건이 복잡할 경우 유지보수가 쉬워집니다.
5. 결론: 언제 어떤 방법을 사용할까?
filter
를 사용하는 경우
- 조건을 함수로 정의하여 재사용성과 확장성을 높이고 싶을 때
- 메모리 사용량을 최소화해야 할 때 (지연 평가 덕분에 큰 데이터를 처리할 때 유리)
리스트 컴프리헨션을 사용하는 경우
- 필터링 조건이 간단하고 가독성이 중요한 경우
- 한 번에 처리할 데이터 크기가 크지 않고, 리스트 생성이 필요한 경우
요약: filter
vs 리스트 컴프리헨션
특성 | filter |
리스트 컴프리헨션 |
---|---|---|
가독성 | 함수 기반으로 조건 분리, 유지보수 용이 | 간결한 구문으로 직관적 표현 가능 |
메모리 사용 | 지연 평가로 메모리 효율적 | 새 리스트 생성으로 메모리 사용 증가 |
조건의 복잡성 | 복잡한 조건에서 함수로 표현 가능 | 간단한 조건에 적합 |
속도 | 큰 차이 없음 (조건에 따라 다름) | 큰 리스트의 경우 메모리 부담 발생 가능 |
filter
와 리스트 컴프리헨션 모두 각각의 장점이 있으므로, 데이터 크기와 조건의 복잡성을 고려해 상황에 맞게 선택하세요! 🎯
'개발 > Python 스터디' 카테고리의 다른 글
[Python] `any`와 `all`로 조건 확인하기: 모든 조건이 만족되나요? (0) | 2024.11.28 |
---|---|
[Python] 중첩 리스트 펼치기(Nested List Flattening): 복잡한 데이터 구조를 간단하게! (0) | 2024.11.27 |
[Python] `functools.reduce`: 복잡한 집계를 간단하게 만드는 매직 (0) | 2024.11.25 |
[Python] 슬라이싱 고급 활용법: 데이터를 자르고, 다루고, 요리하자! (0) | 2024.11.24 |
[Python] 문자열 포매팅의 끝판왕: `f-strings`의 고급 활용법 (0) | 2024.11.23 |