[Python pandas] 문자열 Series 에서 패턴 포함 여부 매칭하기 (test if pattern is contained within a string of a Series) : Series.str.contains(pattern)
Python 분석과 프로그래밍/Python 데이터 전처리 2022. 2. 26. 20:48이번 포스팅에서는 Python pandas의 문자열 Series에서 문자열 패턴 매칭을 통해서 특정 패턴이 포함되어 있는지 여부를 확인하고, 특정 매칭을 포함한 데이터를 가져오는 방법을 소개하겠습니다.
(1) pandas 문자열 Series에서 한개의 문자열 패턴 매칭하기
: Series.str.contains(pattern)
(2) pandas DataFrame에서 한개의 문자열 패턴 매칭이 되는 데이터 가져오기
(3) pandas DataFrame에서 여러개의 문자열 패턴 매팅이 되는 데이터 가져오기
먼저, 예제로 사용할 문자열이 포함된 DataFrame을 만들어보겠습니다. pandas 의 contains() 함수를 사용해서 문자열 뿐만 아니라 NaN 값과 '1004' 숫자도 포함시켜서 문자열 매칭 시 처리방법을 소개하겠습니다.
## importing modules
import numpy as np
import pandas as pd
## creating a pandas DataFrame with strings, NaN, digit
df = pd.DataFrame({
'id': [1, 2, 3, 4, 5, 6, 7]
, 'fruit': ['apple', 'PERSIMON', 'grapes', 'mango', 'peach and perl',
np.NaN,
'1004']
})
print(df)
# id fruit
# 0 1 apple
# 1 2 PERSIMON
# 2 3 grapes
# 3 4 mango
# 4 5 peach and perl
# 5 6 NaN
# 6 7 1004
(1) pandas 문자열 Series에서 한개의 문자열 패턴 매칭하기: Series.str.contains(pattern)
먼저, 위에서 만든 DataFrame에서 'fruit' 칼럼만 가져와서 's1' 이라는 이름의 Series 를 만들어보겠습니다.
## pandas Series
s1 = df['fruit']
print(type(s1)) # padnas.Series
print(s1)
# <class 'pandas.core.series.Series'>
# 0 apple
# 1 PERSIMON
# 2 grapes
# 3 mango
# 4 peach and perl
# 5 NaN
# 6 1004
# Name: fruit, dtype: object
pandas 의 contains() 메소드는 '문자열 Series (Series of a string)' 을 대상으로 문자열 매칭을 해서 Boolean Series 를 반환합니다. contains() 메소드의 구문은 아래와 같습니다.
Series.str.contains(pattern, case=True, flags=0, na=None, regex=True)
이때 Series.str.contains() 메소드는 문자열 Series에 대하여 패턴 매칭(pattern matching)을 할 때 문자열 그 자체(literal itself)와 함께 정규표현식(regex=True: regular expression)까지도 사용해서 패턴 매칭을 할 수 있으며, '대/소문자 구분 (case=True: case sensitive)하며, 'NaN' 값에 대해서는 'NaN'을 반환(na=None)합니다.
아래 예에서는 문자열 Series 's1'에 대해서 문자열 'pe'가 들어있는 패턴 매칭을 해서 Boolean Series 를 반환한 예입니다. (대소문자 구분, NaN은 NaN 반환)
## returning a Series of Booleans using a literal pattern
s1.str.contains('pe')
# 0 False
# 1 False # <-- case sensitive
# 2 True
# 3 False
# 4 True
# 5 NaN # <-- returning NaN for NaN values
# 6 False
# Name: fruit, dtype: object
(2) pandas DataFrame에서 한개의 문자열 패턴 매칭이 되는 데이터 가져오기
pandas DataFrame에서 특정 문자열 칼럼에 대해서 문자열 패턴 매칭한 결과인 Boolean Series 를 이용해서 해당 행의 값만 가져올 수 있습니다. 이때 만약 문자열 패턴 매칭 결과 Boolean Seires 에 NaN 값이 포함되어 있을 경우 아래와 같은 ValueError 가 발생합니다.
ValueError: Cannot mask with non-boolean array containing NA / NaN valu
## ValueError: Cannot mask with non-boolean array containing NA / NaN values
df[df['fruit'].str.contains('pe')]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-5-ee5e3bc73f2f> in <module>
1 ## ValueError: Cannot mask with non-boolean array containing NA / NaN values
----> 2 df[s1.str.contains('pe')]
~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/frame.py in __getitem__(self, key)
2890
2891 # Do we have a (boolean) 1d indexer?
-> 2892 if com.is_bool_indexer(key):
2893 return self._getitem_bool_array(key)
2894
~/opt/anaconda3/lib/python3.8/site-packages/pandas/core/common.py in is_bool_indexer(key)
132 na_msg = "Cannot mask with non-boolean array containing NA / NaN values"
133 if isna(key).any():
--> 134 raise ValueError(na_msg)
135 return False
136 return True
ValueError: Cannot mask with non-boolean array containing NA / NaN values
이 'ValueError: Cannot mask with non-boolean array containing NA/NaN values' 를 해결하기 위해서는 Series.str.contains(pattern, na=False) 처럼 NaN 값을 Boolean의 'False'로 설정해주면 됩니다.
## Specifying na to be False instead of NaN replaces NaN values with False.
df[df['fruit'].str.contains('pe'
, na=False) # specifying NA to be False
]
# id fruit
# 2 3 grapes
# 4 5 peach and perl
만약 문자열 매칭을 할 때 '대/소문자 구분없이 (case insensitive)' 하려면 'case=False' 옵션을 설정해주면 됩니다.
아래 예에서는 case=False 로 설정한 상태에서 'pe' 문자열 매칭을 했더니 'PERSIMON' 대문자도 매칭이 되어서 가져오기가 되었습니다.
## Specifying case sensitivity using case.
df[df['fruit'].str.contains('pe'
, na=False
, case=False) # case = False
]
# id fruit
# 1 2 PERSIMON # <-- case insensitive
# 2 3 grapes
# 4 5 peach and perl
Series.str.contains() 함수에는 정규표현식(regex=True: Regular Expression)을 사용해서 문자열 매칭을 할 수 있습니다. 아래의 예에서는 정규표현식을 이용해서 '숫자가 포함된 ('\\d' : returning any digits)' 문자열을 가져와보겠습니다.
## returning any digit using regular expression
df[df['fruit'].str.contains(
'\\d' # returning any digit
, regex=True # using regular expression
, na=False
)
]
# id fruit
# 6 7 1004
(3) pandas DataFrame에서 여러개의 문자열 패턴 매팅이 되는 데이터 가져오기
이번에는 문자열 매칭을 할 때 '여러개의 문자열 패턴 (multiple strings of pattern)' 과 매칭되는 문자열을 확인하고, pandas DataFrame으로 부터 해당 행의 데이터를 가져와보겠습니다.
여러개의 문자열 패턴을 표현할 때 '|' 가 'or' 를 나타냅니다. 아래의 예의 경우, ['ap' or 'ma' or 'gr'] 이 포함된 문자열을 매칭해서 Boolean String을 반환하고 싶을 때 ['ap'|'ma'|'gr'] 을 패턴으로 입력해주면 됩니다. Python의 내장함수(built-in function) 중에서 join() 메소드를 이용하면 여러개의 문자열을 '|' 구분자(separator)를 넣어서 하나의 문자열로 묶어줄 수 있습니다. ('|'.join(['ap', 'ma', 'gr']) 은 ==> 'ap|ma|gr' 을 반환하며, ==> ['ap' or 'ma' or 'gr'] 을 의미함)
## join() method joins all itmes in a tuple into a string with a separartor
'|'.join(['ap', 'ma', 'gr'])
# 'ap|ma|gr'
## Returning ‘apple’ or ‘mango’ or 'grapes'
## when either expression occurs in a string.
s1.str.contains(
'|'.join(['ap', 'ma', 'gr']) # 'ap|ma|gr', ie. 'ap' or 'ma' or 'gr'
, na=False
, case=False
)
# 0 True
# 1 False
# 2 True
# 3 True
# 4 False
# 5 False
# 6 False
# Name: fruit, dtype: bool
이제 pandas DataFrame 에서 'fruit' 칼럼에서 'ap' or 'ma' or 'gr' 문자열이 포함되어 있는 모든 행을 가져와보겠습니다.
## indexing data using a Series of Booleans
df[df['fruit'].str.contains(
'|'.join(['ap', 'ma', 'gr'])
, na=False
, case=False
)
]
# id fruit
# 0 1 apple
# 2 3 grapes
# 3 4 mango
[ Reference ]
[1] pandas.Series.str.contains()
: https://pandas.pydata.org/docs/reference/api/pandas.Series.str.contains.html
이번 포스팅이 많은 도움이 되었기를 바랍니다.
행복한 데이터 과학자 되세요! :-)