KEEP GOING
[python] 문자열 치환 총 정리 및 성능 비교하기(str.translate, str.replace, re.sub) 본문
목차
Intro
데이터 전처리 과정은 분석 결과/ 모델 성능에 중요한 영향을 미치기에,
데이터 전처리 과정에서 데이터 정제에 속하는 문자열을 치환하는 방법을 제대로 이해하고자 합니다.
파이썬 문자열 내장 함수인 str.translate(), str.replace(), 그리고 re 모듈을 활용한 re.sub을 이용한 문자열 치환 방법을 알아보겠습니다.
* 데이터 전처리: 데이터 정제 > 결측값 처리 > 이상값 처리 > 분석 변수 처리순으로 진행됨
* 데이터 정제: 결측값(missing value)을 채우거나 이상값(outlier)을 제거하는 과정으로 데이터의 신뢰도를 높이는 작업
str.translate
s = '\nNew Jeans\t'
table = s.maketrans({'\n':'', '\t':''})
print(s.translate(table))
translate 함수를 사용할 경우, 문자열의 여러 문자를 한 번에 치환할 수 있습니다.
maketrans 메서드는 매개변수로 딕셔너리를 필요로 합니다. key에 치환할 대상을 그리고 치환하려는 값을 value에 넣어줍니다. 이 치환 테이블을 table이라는 변수에 저장하고 이를 다시 translate 메서드에 매개변수로 넣으면 치환된 값을 리턴할 수 있습니다.
그 결과는 다음과 같습니다.
New Jeans
하지만 translate 함수의 치명적인 단점이있습니다. 치환하고자 하는 값의 길이가 2 이상일 경우 다음과 같은 에러가 발생합니다. (앞선 예제에서 '\n', '\t'의 길이는 모두 1입니다.)
ValueError: string keys in translate table must be of length 1
따라서 치환하려는 값이 2글자 이상일 경우에는 다른 메서드를 사용하는 것이 좋습니다.
s = "New Jeans, Hype Boy"
x = "New Jeans" #치환할 대상
y = "new jeans" #바뀌는 값
table = s.maketrans(x, y)
print(s.translate(table))
딕셔너리가 아니라 매개변수에 두 변수를 집어 넣어 값을 대체할 수도 있습니다. 하지만 x와 y의 각각의 자리는 서로 1:1 대응을 이루기 때문에 자릿수가 일치해야 합니다. 즉, y가 "뉴진스"라면 다음과 같은 에러가 발생합니다.
ValueError: the first two maketrans arguments must have equal length
때문에 maketrans 메서드에 들어갈 두 멤버변수는 길이가 동일해야 합니다.
str.replace
s = "내가 만든 쿠키~ 너를 위해 구웠지 쿠키 쿠키"
print(s.replace("쿠키", "cookie"))
replace는 대표적인 파이썬 문자열 치환 메서드입니다. replace에는 바꾸고자 하는 대상과 바꾸려는 값을 적어주면 됩니다.
위 예제는 다음과 같은 값을 반환하는데
내가 만든 cookie~ 너를 위해 구웠지 cookie cookie
그 이유는 replace가 문자열에 포함된 모든 대상(쿠키)을 전부 변환(cookie)해주기 때문입니다.
re.sub
import re
re.sub(패턴, 바꿀 문자열, 문자열, 바꿀 횟수)
정규표현식을 사용하여 문자열을 치환하는 방법입니다. 문자열을 바꾸기 위해 re 모듈의 sub 메서드를 필요로 합니다.
만약 바꿀 횟수를 지정하지 않는다면 replace와 마찬가지로 찾아낸 모든 문자열을 바꿔줍니다.
import re
s = "내가 만든 쿠키~ 너를 위해 구웠지 쿠키 쿠키"
print(re.sub("쿠키", "cookie", "내가 만든 쿠키~ 너를 위해 구웠지 쿠키 쿠키"))
앞서 사용한 예제를 가져와 적용해보면 마찬가지로 같은 결과가 나옵니다.
내가 만든 cookie~ 너를 위해 구웠지 cookie cookie
만약에 re.sub의 매개변수로 2를 추가해줬다면 마지막 cookie는 변경되지 않고 쿠키로 남아있을 것입니다.
하지만 정규표현식을 결코 쉽게 보면 안 됩니다. 조금 더 어려운 문제를 가져와 보겠습니다.
print(re.sub('([a-z]+) ([0-9]+)', '\\2 \\1 \\2 \\1', 'password 486'))
정규표현식을 그룹으로 묶으면 바꿀 문자열에서 \\숫자 형식으로 사용할 수 있습니다.
a부터 z까지 모든 소문자 알파벳을 그룹 1로 묶고 0부터 9까지의 모든 숫자를 그룹 2로 묶었습니다.
결과값은 그룹 2 1 2 1 순으로 다음과 같이 출력됩니다.
486 password 486 password
str.translate, str.replace, re.sub 성능 비교
import time
import re
s = """\
This is according to new data from IT research firm Synergy Research Group,\
which shows enterprise spending on cloud infrastructure services in the fourth quarter of 2022 reached $61.6 billion.\
This represents a spending increase of 21 percent year over year, or about $10 billion more than fourth quarter 2021.\
“Microsoft in particular had a strong quarter,” John Dinsdale, chief analyst at Synergy Research, told CRN in an email.
"""
for i in range(20):
s += (' ' + s)
start = time.time()
table = s.maketrans({" ": "-"})
r1 = s.translate(table)
end = time.time()
print("translate time:", end - start)
start = time.time()
r2 = s.replace(" ", "-")
end = time.time()
print('replace time:', end - start)
start = time.time()
r3 = re.sub(" ", "-", s)
end = time.time()
print("sub time:", end - start)
우선 성능 차이를 확연히 비교하기 위해 데이터의 size를 키워봤습니다.
대상 문자열 s로 반복문을 돌아 20 제곱만큼 확장된 문자열 s로 만들었습니다.
그리고 time 모듈을 활용하여 시간을 비교해본 결과는 아래와 같습니다.
translate time: 25.2299907207489
replace time: 0.4854011535644531
sub time: 17.2787184715271
replace의 속도가 압도적으로 빠르고 sub와 translate의 속도가 현저히 느린 것을 알 수 있었습니다.
정규표현식은 복잡한 문자열을 처리하기 용이하지만 속도가 느리고 작성하기에 어려움이 있습니다.
그리고 replace는 빠르긴 하나 특수한 조건을 걸어 복잡한 문자열을 처리하기에는 한계가 있습니다.
따라서 상황에 맞게 적절한 메서드를 사용하는 것이 바람직하겠네요.
이렇게 replace, re.sub, translate 메서드를 알아보고 성능까지 파악해보는 시간을 가져봤습니다.
'python' 카테고리의 다른 글
[python] 파이썬 정규표현식(regex) 사용법([], ^, |, +, ?, ., *, $) 정리 및 연습 사이트 추천 (0) | 2023.05.29 |
---|---|
[python] 파이썬으로 시작하는 통계 데이터 분석 : 입문 - 탐색적 데이터 분석(기술통계분석, EDA) 실습(Part1) (0) | 2022.10.25 |
[python] 파이썬으로 시작하는 통계 데이터 분석 : 입문 - 데이터 전처리 실습(Part1) (0) | 2022.10.25 |
[python] 파이썬으로 시작하는 통계 데이터 분석 : 입문 - 데이터 전처리 실습(Part2) (0) | 2022.10.25 |
[python] 로깅(logging) 라이브러리 사용법(setLevel, fileHandler, StreamHandler) (0) | 2022.10.13 |