[Pandas] str regex (extract / split / replace)
Pandas regex, Pandas str extract, Pandas str split, Pandas str regex, Pandas 정규식, pandas str.extract, pandas str.replace regex
정의
Series.str 의 정규식 기반 메서드. 패턴 추출, 분리, 치환 의 핵심.
Pandas str accessor 의 정규식 특화 부분. 기본 문자열 메서드는 Pandas str pattern 참고.
사용 상황
- 로그 문자열에서 IP, 날짜, 에러 코드 등을 컬럼으로 추출할 때
- 전화번호/이메일 등 비정형 데이터를 정규화할 때
- HTML/JSON 문자열에서 특정 패턴을 파싱할 때
- 문자열 내 여러 매치를 모두 찾아야 할 때
str regex 메서드 흐름
flowchart LR
STR["Series (문자열)"] --> METHOD{"메서드"}
METHOD -->|"str.extract"| EX["첫 매치 → DataFrame"]
METHOD -->|"str.extractall"| EXA["모든 매치 → MultiIndex DataFrame"]
METHOD -->|"str.findall"| FA["모든 매치 → list per row"]
METHOD -->|"str.replace"| REP["치환 → Series"]
METHOD -->|"str.split"| SP["분리 → list / DataFrame"]
METHOD -->|"str.contains"| CON["포함 여부 → bool Series"]
METHOD -->|"str.match"| MAT["시작 매치 → bool Series"]
METHOD -->|"str.fullmatch"| FM["전체 매치 → bool Series"]
str.extract: 캡처 그룹으로 추출
python
import pandas as pd
s = pd.Series(['Alice (30)', 'Bob (25)', 'Charlie (40)'])
result = s.str.extract(r'(w+) ((d+))')
result.columns = ['name', 'age']
print(result) 결과
name age
0 Alice 30
1 Bob 25
2 Charlie 40- 캡처 그룹 수 = 결과 DataFrame 의 컬럼 수
- 매치 없는 행은 NaN
named group: 컬럼명 자동 지정
s.str.extract(r'(?P<name>\w+) \((?P<age>\d+)\)')
# 컬럼이 자동으로 name, age 가 됨
expand=False: 단일 그룹 → Series
s.str.extract(r'(\d+)', expand=False) # Series 반환
s.str.extract(r'(\d+)', expand=True) # DataFrame 반환 (기본)
str.extractall: 모든 매치
s = pd.Series(['Alice and Bob', 'Charlie and Dave'])
result = s.str.extractall(r'(\w+)')
# 한 행이 여러 매치를 가지면 MultiIndex 로 expand
python
import pandas as pd
s = pd.Series(['price: 100, qty: 5', 'price: 200, qty: 3'])
result = s.str.extractall(r'(d+)')
print(result) 결과
0
match
0 0 100
1 5
1 0 200
1 3str.split: 분리
s.str.split(',') # list 반환
s.str.split(',', expand=True) # DataFrame 으로 분리
s.str.split(',', n=1) # 최대 1번 분리
s.str.split(r'\s+', regex=True) # 정규식 분리 (pandas 1.4+)
df = pd.DataFrame({'full_name': ['Alice Smith', 'Bob Johnson']})
df[['first', 'last']] = df['full_name'].str.split(' ', expand=True)
str.replace: 치환
s.str.replace('a', 'A') # 단순 치환 (regex=False)
s.str.replace(r'\d+', 'X', regex=True) # 정규식
s.str.replace(r'(\w+)@(\w+)', r'\2 / \1', regex=True) # 그룹 참조
IMPORTANT
pandas 2.0 부터 str.replace 의 regex 기본값이 False. 정규식을 쓰려면 regex=True 를 명시해야 한다.
# 2.0+ 에서 경고 없이 쓰는 패턴
s.str.replace(r'\d+', 'X', regex=True) # ✓ 명시
s.str.replace('abc', 'ABC', regex=False) # ✓ 명시
str.findall: 모든 매치를 리스트로
s = pd.Series(['call me 010-1234-5678', 'email me at a@b.com'])
s.str.findall(r'\d+')
# 0 [010, 1234, 5678]
# 1 []
extractall 과 달리 각 행에 list 를 반환한다. 개수가 가변적일 때 유용.
str.match vs str.contains vs str.fullmatch
| 메서드 | 매칭 위치 | 동등 Python |
|---|---|---|
contains | 어느 위치든 | re.search |
match | 시작부터 | re.match |
fullmatch | 전체 일치 | re.fullmatch |
s = pd.Series(['abc', 'abcd', 'xabc'])
s.str.contains(r'^abc$') # [True, False, False]
s.str.match(r'abc') # [True, True, False]
s.str.fullmatch(r'abc') # [True, False, False]
na 처리
s = pd.Series(['abc', None, 'xyz'])
s.str.contains('a', na=False) # NaN → False
s.str.contains('a', na=True) # NaN → True
실전 패턴
이메일 도메인 추출
df['domain'] = df['email'].str.extract(r'@(.+)$')
df['domain'].value_counts()
전화번호 정규화
df['phone'] = (
df['phone']
.str.replace(r'\D', '', regex=True) # 숫자만
.str.replace(r'^(\d{3})(\d{4})(\d{4})$', r'\1-\2-\3', regex=True)
)
로그 파싱
# '2024-01-15 09:00:00 ERROR Something failed'
log = pd.Series([
'2024-01-15 09:00:00 ERROR Something failed',
'2024-01-15 09:01:00 INFO Request received',
])
parsed = log.str.extract(
r'(?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) (?P<level>\w+)\s+(?P<msg>.+)'
)
URL 에서 경로 추출
df['path'] = df['url'].str.extract(r'https?://[^/]+(/[^?#]*)')
df['query'] = df['url'].str.extract(r'\?(.+)$')
여러 패턴 중 하나 매치
pattern = r'(error|warning|critical)'
df['level'] = df['log'].str.extract(pattern, flags=0)
df[df['log'].str.contains(pattern, case=False, regex=True)]
성능
| 방법 | 속도 | 비고 |
|---|---|---|
str.extract | 보통 | 행별 re.search |
str.contains | 빠름 | 단순 패턴은 빠름 |
apply(re.search) | 느림 | Python 루프 |
str.extractall | 느림 | MultiIndex 생성 비용 |
# 대용량에서 contains 가 extract 보다 빠름
# 존재 여부만 확인할 때는 contains 사용
df[df['text'].str.contains(r'\d{3}-\d{4}', regex=True)]
함정
1. extract 의 반환 타입
# 단일 그룹: expand=True (기본) → DataFrame
s.str.extract(r'(\d+)') # DataFrame
# 단일 그룹: expand=False → Series
s.str.extract(r'(\d+)', expand=False) # Series
2. 욕심쟁이 vs 게으른 수량자
s = pd.Series(['<a>text</a>'])
s.str.extract(r'<(.+)>') # 욕심쟁이: 'a>text</a' 매치
s.str.extract(r'<(.+?)>') # 게으른: 'a' 매치
3. multiline / dotall 플래그
import re
s.str.extract(r'(.+)', flags=re.DOTALL) # . 이 줄바꿈도 매치
s.str.contains(r'^abc', flags=re.MULTILINE) # 각 줄의 시작
4. regex=False 기본값 (pandas 2.0+)
# ❌ pandas 2.0+ 에서 FutureWarning 또는 의도와 다른 동작
s.str.replace(r'\d+', 'X')
# ✓ 명시
s.str.replace(r'\d+', 'X', regex=True)
5. extractall 의 MultiIndex
result = s.str.extractall(r'(\d+)')
# index 가 (원래 index, match 번호) 의 MultiIndex
# 원래 index 로 돌아가려면
result.reset_index(level='match', drop=True)
관련 위키
이 글의 용어 (5개)
- [Pandas] .str accessorpandas
- 정의 는 Series 의 각 문자열 원소에 벡터화된 문자열 메서드 를 적용하는 accessor. Python 의 거의 모든 메서드를 NaN-aware 로 제공한다. accesso…
- [Pandas] Boolean Indexingpandas
- 정의 Boolean Indexing 은 True/False 의 Series 를 인덱서로 전달 해 행을 선택하는 패턴. pandas 의 가장 흔한 필터링 방법. 마스크 생성과 적용…
- [Pandas] dropna / fillnapandas
- 정의 - : NaN 이 있는 행/열 제거 - : NaN 을 특정 값으로 대체 데이터 분석의 가장 기본적인 결측치 처리. 사용 상황 - CSV 로드 후 빈 셀이 NaN 으로 읽혔을…
- [Pandas] str.contains / startswith / endswithpandas
- 정의 문자열 Series 에서 패턴 매칭 으로 필터링/검색하는 메서드들. SQL 의 , 패턴에 해당하며, accessor 를 통해 접근한다. 메서드 전체 지도 contains -…
- [Pandas] value_countspandas
- 정의 는 각 고유값의 등장 빈도 를 내림차순 Series 로 반환. SQL 의 . pandas 1.1+ 부터는 도 가능 (여러 컬럼 조합). 기본 <CodeWithOutput l…
💬 댓글