正規表現によるパターンマッチング
正規表現を使い、.str.extract()、.str.contains()、.str.match()で部分文字列を抽出してパターンを確認します。
「正規表現によるパターンマッチング」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
Pandasで正規表現を使う理由
正規表現(regex)は、文字列のパターンを記述するための言語です。Pandasでは、.strアクセサを通して、contains()、match()、extract()、findall()、replace()で正規表現を利用できます。単純なcontainsやstartswithのチェックでは複雑すぎるパターンには、正規表現が適しています。たとえば、メールアドレスの形式検証、自由記述テキストからの電話番号の抽出、メモ列に含まれるすべての金額の検索などです。
import pandas as pd
df = pd.DataFrame({
'text': ['Order #12345 placed', 'No order', 'Ref #67890 paid', 'Refund for #11111']
})
# Find rows that contain an order number (# followed by 5 digits)
has_order = df['text'].str.contains(r'#\d{5}', regex=True)
print(df[has_order])
# text
# 0 Order #12345 placed
# 2 Ref #67890 paid
# 3 Refund for #11111.str.contains()と正規表現
regex=True(デフォルト)で.str.contains(pattern)を使うと、文字列内のどこかでパターンが一致した箇所についてTrueとなるbooleanのSeriesが返されます。一致する位置を限定するには、^(先頭)や$(末尾)などのアンカーを使用します。形式要件に一致するフィールドを持つ行のフィルタリング、たとえば有効な日付パターンや正しい形式のコードの確認などに利用できます。
import pandas as pd
df = pd.DataFrame({
'code': ['US-001', 'UK-042', 'DE-18', 'FR-', 'us-003']
})
# Valid format: two uppercase letters, hyphen, 3 digits
valid = df['code'].str.contains(r'^[A-Z]{2}-\d{3}$', regex=True)
print(df['code'][valid].tolist())
# ['US-001', 'UK-042'].str.match()で先頭から照合する
.str.match(pattern)は、各文字列がパターンで始まっているかを確認します(文字列の先頭に固定されます)。これは文字列内のどこでも検索するcontains()との違いです。文字列の先頭部分だけを確認したい場合はmatch()を使用し、文字列全体がパターンに一致する必要がある場合はfullmatch()を使用します。
import pandas as pd
df = pd.DataFrame({'id': ['ORD001', 'ORD002', 'RET003', 'ORDXYZ']})
# Match rows whose ID starts with 'ORD' followed by digits
orders = df['id'].str.match(r'ORD\d+')
print(df[orders])
# id
# 0 ORD001
# 1 ORD002
# match() is anchored at start, so 'ORDXYZ' (XYZ not digits) is excluded.str.extract()でキャプチャグループを抽出する
.str.extract(pattern)は、正規表現パターン内のキャプチャグループ()を使って、一致した文字列から特定の部分を取り出します。キャプチャグループごとに1列を持つDataFrameを返します。各文字列から返されるのは最初に一致した部分だけです。自由記述テキストに埋め込まれた数値、日付、IDなどの構造化データの抽出に最適です。
import pandas as pd
df = pd.DataFrame({
'notes': ['Shipped on 2024-01-15', 'Delivered on 2024-03-20', 'Pending', 'Shipped on 2024-07-04']
})
# Extract the date (YYYY-MM-DD) from the notes column
dates = df['notes'].str.extract(r'(\d{4}-\d{2}-\d{2})')
df['shipped_date'] = dates[0]
print(df[['notes', 'shipped_date']])
# notes shipped_date
# 0 Shipped on 2024-01-15 2024-01-15
# 1 Delivered on 2024-03-20 2024-03-20
# 2 Pending NaN
# 3 Shipped on 2024-07-04 2024-07-04名前付きキャプチャグループ
(?P<name>...)構文を使うと、キャプチャグループに名前を付けられます。str.extract()で名前付きグループを使用すると、結果のDataFrameではその名前が自動的に列見出しとして使われます。そのため、後から列名を変更しなくても、出力内容が明確になります。
import pandas as pd
df = pd.DataFrame({
'entry': ['Alice (25, Engineer)', 'Bob (30, Manager)', 'Carol (28, Analyst)']
})
# Named capturing groups
extracted = df['entry'].str.extract(
r'(?P<name>\w+) \((?P<age>\d+), (?P<role>\w+)\)'
)
print(extracted)
# name age role
# 0 Alice 25 Engineer
# 1 Bob 30 Manager
# 2 Carol 28 Analyst.str.extractall()で複数の一致を抽出する
.str.extractall(pattern)は、各文字列でパターンに一致するすべての箇所を検索します(最初の1件だけではありません)。MultiIndexを持つDataFrameを返し、外側のレベルは元の行インデックス、内側のレベル(match)は行ごとの一致件数を表します。自由記述フィールドからすべての数値、URL、キーワードを抽出する場合に便利です。
import pandas as pd
df = pd.DataFrame({
'text': ['Call 555-1234 or 555-5678', 'Contact 800-9000', 'No numbers']
})
# Extract all phone patterns
all_phones = df['text'].str.extractall(r'(\d{3}-\d{4})')
print(all_phones)
# 0
# match
# 0 0 555-1234
# 1 555-5678
# 1 0 800-9000.str.findall()で一致結果のリストを取得する
.str.findall(pattern)はリストのSeriesを返します。各リストには、その行の文字列で見つかったすべての一致結果が含まれます。extractall()とは異なり、MultiIndexは作成されず、各行に一致結果のリストが割り当てられます。結果をフラットな構造で保持したい場合や、行ごとの一致件数を数えたい場合に便利です。
import pandas as pd
df = pd.DataFrame({
'text': ['Buy 3 items for $10 each', 'Save $5 on 2 products', 'No deal']
})
# Find all dollar amounts
df['prices'] = df['text'].str.findall(r'\$\d+')
df['price_count'] = df['prices'].str.len()
print(df[['text', 'prices', 'price_count']])
# text prices price_count
# 0 Buy 3 items for $10 each [$10] 1
# 1 Save $5 on 2 products [$5] 1
# 2 No deal [] 0re.IGNORECASEで大文字と小文字を区別せずに照合する
デフォルトでは、Pandasの正規表現は大文字と小文字を区別します。flags=re.IGNORECASE(またはre.I)を渡すと、パターンで大文字と小文字を区別しなくなります。これにより、'python'、'Python'、'PYTHON'を同じように照合したい場合でも、[Pp][Yy][Tt][Hh][Oo][Nn]のようなORパターンを記述する必要がなくなります。
import pandas as pd
import re
df = pd.DataFrame({
'skill': ['Python', 'JAVA', 'javascript', 'PyThOn developer', 'SQL']
})
# Case-insensitive search for python
mask = df['skill'].str.contains('python', flags=re.IGNORECASE, regex=True)
print(df[mask])
# skill
# 0 Python
# 3 PyThOn developer完全一致で形式を検証する
.str.fullmatch(pattern)(Pandas 1.1で追加)は、文字列全体がパターンに一致する場合にのみTrueを返します。部分文字列に一致するcontains()とは異なり、fullmatchは^...$でアンカーを指定するのと同等です。メールアドレス、電話番号、郵便番号など、厳密なスキーマを持つフィールドの形式準拠を検証する最も安全な方法です。
import pandas as pd
df = pd.DataFrame({
'email': ['alice@example.com', 'bob_at_work', 'carol@test', 'dave@org.co']
})
# Simple email validation: word@word.word
valid_email = df['email'].str.fullmatch(r'[\w.+-]+@[\w-]+\.[\w.]+')
print(df[valid_email])
# email
# 0 alice@example.com
# 3 dave@org.co正規表現の後方参照で置換する
str.replace(pattern, repl, regex=True)を使用すると、置換文字列にr'\1'のような後方参照を含めて、最初のグループ()でキャプチャした内容を参照できます。これにより、MM/DD/YYYYをYYYY-MM-DDに変更したり、一致した単語をHTMLタグで囲んだりするなど、高度な形式変更が可能になります。
import pandas as pd
df = pd.DataFrame({'phone': ['(555) 123-4567', '(800) 555-0199', '(212) 867-5309']})
# Reformat to 555-123-4567
df['phone_clean'] = df['phone'].str.replace(
r'\((\d{3})\) (\d{3})-(\d{4})',
r'\1-\2-\3',
regex=True
)
print(df)
# phone phone_clean
# 0 (555) 123-4567 555-123-4567
# 1 (800) 555-0199 800-555-0199
# 2 (212) 867-5309 212-867-5309正規表現ベースのデータ抽出器を構築する
ここでは、名前付きグループを使って、複雑なメモ列から商品SKUと価格を抽出する、実践的なエンドツーエンドの例を示します。このような抽出は、複数のフィールドが1つのテキストフィールドに連結されているレガシーシステムからデータを取り込む場合によく行われます。
import pandas as pd
df = pd.DataFrame({
'note': [
'SKU:A001 price:$49.99 in stock',
'SKU:B202 price:$12.50 low stock',
'No SKU available'
]
})
extracted = df['note'].str.extract(
r'SKU:(?P<sku>\w+).*price:\$(?P<price>[\d.]+)'
)
print(extracted)
# sku price
# 0 A001 49.99
# 1 B202 12.50
# 2 NaN NaNクイックチェック
Pandasでの正規表現によるパターン照合についての理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、str.contains(regex)でパターンに基づいて行をフィルタリングできること、str.extract()で最初の一致をDataFrameの列に抽出できること(出力内容を明確にするには名前付きグループを使用します)、str.extractall()で行ごとのすべての一致をMultiIndex付きで取得できること、そしてstr.fullmatch()で文字列全体がパターンに準拠しているか検証できることを学びました。次は、複数のテキスト列を結合してクリーニングします。
よくある質問
「正規表現によるパターンマッチング」レッスンは無料ですか?
はい。「正規表現によるパターンマッチング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
「正規表現によるパターンマッチング」で何を学びますか?
正規表現を使い、.str.extract()、.str.contains()、.str.match()で部分文字列を抽出してパターンを確認します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Pandas & NumPy Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「正規表現によるパターンマッチング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPandas & NumPy Academyレッスンでコードを書いて実行できますか?
はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- .strアクセサー
- 文字列の分割と置換
- 正規表現によるパターンマッチング
- テキスト列の結合とクリーニング