Pandas Series.str.extract: 文字列からパターンを抽出する
Pandas Series.str.extract: 文字列からパターンを抽出する
pandas.Series.str.extract
メソッドは、pandas
ライブラリの Series
オブジェクトから、正規表現パターンに一致する部分文字列を抽出するために使用されます。データ分析において、テキストデータから特定の情報を取り出すために有用なツールです。
使い方
import pandas as pd
# データの準備
data = pd.Series(["2023-07-15 13:22:00", "2023-07-16 08:45:00", "2023-07-17 10:10:10"])
data.name = "日時"
# 年月日を抽出
extracted_data = data.str.extract(r"(\d{4})-(\d{1,2})-(\d{1,2})", expand=False)
print(extracted_data)
出力
0 1 2
0 2023 07 15
1 2023 07 16
2 2023 07 17
解説
- 上記の例では、
data
というSeries
オブジェクトに、日時情報を含む文字列が格納されています。 str.extract
メソッドは、正規表現パターンr"(\d{4})-(\d{1,2})-(\d{1,2})"
を引数として受け取り、data
内の各文字列から一致する部分文字列を抽出します。r"
は、正規表現パターンであることを示す記号です。(\d{4})
は、4桁の数字を表すパターンです。-
は、文字通りのハイフンを表します。expand=False
オプションは、抽出結果をSeries
オブジェクトとして返すことを指定します。
応用例
- ウェブスクレイピングから取得したHTMLテキストから特定の情報を取り出す
- ログファイルからエラーメッセージを抽出する
- 顧客情報データから住所や電話番号を抽出する
pandas.Series.str.extract
メソッドは、複数のキャプチャグループを定義することができます。- 抽出結果を
DataFrame
オブジェクトとして返すことも可能です。
この例では、Beautiful Soup を使って HTML から住所をスクレイピングし、pandas.Series.str.extract
で住所の各要素を抽出します。
import pandas as pd
from bs4 import BeautifulSoup
# HTML データ
html_data = """
<div class="address">
<span class="street">123 Main Street</span>
<span class="city">Anytown</span>,
<span class="state">CA</span>
<span class="zip-code">95743</span>
</div>
<div class="address">
<span class="street">456 Elm Street</span>
<span class="city">Springfield</span>,
<span class="state">IL</span>
<span class="zip-code">62704</span>
</div>
"""
# BeautifulSoup を使ってパース
soup = BeautifulSoup(html_data, 'lxml')
# 住所を含む要素を取得
address_elements = soup.find_all('div', class_='address')
# 住所情報を含む Series を作成
addresses = pd.Series([element.text for element in address_elements])
# 正規表現で住所の各要素を抽出
extracted_addresses = addresses.str.extract(
r"""
(?P<street>\w+ \w+ Street) # 番地と通り名
, (?P<city>\w+) # 市区町村
, (?P<state>\w{2}) # 都道府県
\s (?P<zip-code>\d{5}) # 郵便番号
""",
expand=True
)
# 結果を表示
print(extracted_addresses)
street city state zip-code
0 123 Main Street Anytown CA 95743
1 456 Elm Street Springfield IL 62704
この例では、pandas.Series.str.extract
を使って、ログファイルからエラーメッセージを抽出します。
import pandas as pd
# ログファイルデータ
log_data = """
ERROR: An error occurred while processing the data.
WARNING: Potential issue detected.
INFO: Completed task successfully.
ERROR: Unable to connect to the database.
"""
# ログデータを Series に格納
log_entries = pd.Series(log_data.splitlines())
# エラーメッセージのみを抽出
error_messages = log_entries.str.extract(r"^ERROR: (.*)", expand=False)
# 結果を表示
print(error_messages)
0 An error occurred while processing the data.
3 Unable to connect to the database.
import pandas as pd
# 顧客情報データ
customer_data = """
Alice Johnson, 123 Main St, Anytown, CA 95743, (555) 555-5555
Bob Williams, 456 Elm St, Springfield, IL 62704, (444) 444-4444
Charlie Brown, 789 Oak Ave, Oakville, NY 12345, (333) 333-3333
"""
# 顧客情報データを Series に格納
customer_info = pd.Series(customer_data.split('\n'))
# 住所と電話番号を抽出
extracted_info = customer_info.str.extract(
r"""
(?P<name>\w+ \w+), # 氏名
\s (?P<address>.+), # 住所
\s (?P<zip-code>\d{5}), # 郵便番号
\s \((?P<phone_number>\d{3}-\d{3}-\d{4})\)
""",
expand=True
)
# 結果を表示
print(extracted_info)
Pandas.Series.str.extract の代替方法
str.split() と str.get() の組み合わせ
- 利点:
- シンプルで分かりやすい構文
- 特定のパターンのみを抽出したい場合に適している
- 欠点:
- 複数のキャプチャグループを抽出するには不向き
- 正規表現よりも複雑なパターンを処理するのが難しい
import pandas as pd
data = pd.Series(["2023-07-15 13:22:00", "2023-07-16 08:45:00", "2023-07-17 10:10:10"])
data.name = "日時"
# 年月日を抽出
extracted_data = data.str.split('-').str.get([0, 1, 2])
print(extracted_data)
0 1 2
0 2023 07 15
1 2023 07 16
2 2023 07 17
re.findall() 関数
- 利点:
- 欠点:
pandas
APIの一部ではないため、データフレームに直接適用できない- 処理速度が
pandas.Series.str.extract
よりも遅い場合がある
import pandas as pd
import re
data = pd.Series(["2023-07-15 13:22:00", "2023-07-16 08:45:00", "2023-07-17 10:10:10"])
data.name = "日時"
# 年月日を抽出
def extract_date(text):
return re.findall(r"(\d{4})-(\d{1,2})-(\d{1,2})", text)
extracted_data = data.apply(extract_date)
print(extracted_data)
0 [('2023', '07', '15')]
1 [('2023', '07', '16')]
2 [('2023', '07', '17')]
Name: 日時, dtype: object
lambda 関数
- 利点:
- 欠点:
import pandas as pd
data = pd.Series(["2023-07-15 13:22:00", "2023-07-16 08:45:00", "2023-07-17 10:10:10"])
data.name = "日時"
# 年月日を抽出
extracted_data = data.str.extract(lambda x: re.findall(r"(\d{4})-(\d{1,2})-(\d{1,2})", x))
print(extracted_data)
0 [('2023', '07', '15')]
1 [('2023', '07', '16')]
2 [('2023', '07', '17')]
Name: 日時, dtype: object
カスタム関数
- 利点:
- 複雑な抽出ロジックを柔軟に実装可能
- コードの再利用性が高い
- 欠点:
- コード量が増える
- テストが必要
import pandas as pd
def extract_date(text):
match = re.search(r"(\d{4})-(\d{1,2})-(\d{1,2})", text)
if match:
return match.groups()
else:
return None
data = pd.Series(["2023-