【Pandas文字列操作】正規表現でテキストから情報を抽出して新列を生成する
データ分析では、テキストデータから特定のパターンに合致する情報(例: 製品コード、URLの一部、日付など)を抽出し、それを新たな列としてDataFrameに追加したい場面が頻繁にあります。特に、文字列のパターンが複雑で、単純な部分文字列検索では対応できない場合、**正規表現(Regular Expression)**の力が不可欠になります。
Pandasは、Seriesの文字列操作メソッド(.strアクセサ)と正規表現を組み合わせることで、この複雑なテキスト抽出を効率的に行えます。この記事では、Pandasを使って文字列から正規表現で情報を抽出し、新しい列を生成する主要なテクニックを、短いサンプルコードと丁寧な解説を交えてご紹介します。
正規表現とテキスト抽出の重要性
正規表現は、文字列のパターンを記述するための強力な記法です。特定の文字の並び、数字の連続、特定の記号の有無など、様々なルールを定義して文字列を検索・置換・抽出できます。
テキストから情報を抽出し、新たな列を生成することがデータ分析で重要な理由は以下の通りです。
-
非構造化データの活用: ログデータ、レビュー、商品説明文など、一見して分析しにくいテキスト情報から、構造化された意味のあるデータを引き出します。
-
特徴量エンジニアリング: 機械学習モデルの入力として、テキストから抽出した特定の情報を新たな特徴量として利用できます。
-
データクレンジング: テキスト内の表記ゆれを統一したり、誤った形式のデータを特定したりする前処理に応用できます。
-
データの整形: 複数の情報が混在する1つの文字列から、必要な部分だけを分離して扱いやすい形にします。
文字列から正規表現で抽出する基本: str.extract()
PandasのSeries.str.extract()メソッドは、正規表現を使って文字列から情報を抽出し、新しいDataFrameの列として返す最も便利な方法です。
単一の情報を抽出して新しい列を生成
正規表現で抽出したいパターンを**グループ化(括弧()で囲む)**して指定します。
import pandas as pd
# サンプルDataFrameの作成
df = pd.DataFrame({
'商品コード': ['XYZ-123_RED', 'ABC-456_BLUE', 'DEF-789_GREEN', 'GHI-011_YELLOW'],
'商品説明': ['高性能スマホ (型番:XYZ-123)', '小型カメラ (型番:ABC-456)', 'ノートPC (型番:DEF-789)']
})
print("オリジナルDataFrame:\n", df)
# '商品コード'から色情報を抽出して'色'列を生成
# 正規表現: _(任意の文字の連続) -> _に続く部分を抽出
df['色'] = df['商品コード'].str.extract(r'_(.+)')
print("\n'商品コード'から色情報を抽出後:\n", df)
解説:
-
r'_(.+)': 正規表現パターンを定義します。rプレフィックスは生文字列(Raw String)であることを示し、バックスラッシュのエスケープが不要になります。-
_: リテラルなアンダースコアにマッチします。 -
(): グループ化を表します。この括弧内のパターンにマッチした部分が抽出されます。 -
.: 任意の一文字にマッチします(改行を除く)。 -
+: 直前の文字が1回以上繰り返されることにマッチします。
つまり、_の後に続く任意の文字の並びを全て抽出するという意味です。
-
-
df['商品コード'].str.extract():'商品コード'列の各文字列に正規表現を適用し、抽出された値が新しいSeriesとして返されます。 -
新しいSeriesを
df['色']として代入することで、新たな列がDataFrameに追加されます。
複数の情報を同時に抽出する
正規表現で複数のグループを定義することで、一度に複数の情報を抽出し、それぞれを新しい列として生成できます。
# '商品説明'から「型番」と「色(今回はなし)」を抽出
# 正規表現: 型番:(英数字3文字)-(数字3文字)
df[['型番1', '型番2']] = df['商品説明'].str.extract(r'型番:([A-Z]{3})-([0-9]{3})')
print("\n'商品説明'から複数の情報を抽出後:\n", df)
解説:
-
r'型番:([A-Z]{3})-([0-9]{3})': 2つのグループを定義しています。-
[A-Z]{3}: 大文字アルファベットが3回繰り返されることにマッチ。 -
[0-9]{3}: 数字が3回繰り返されることにマッチ。
つまり、型番:の後に続く「大文字3文字-数字3文字」のパターンをそれぞれ抽出します。
-
-
df[['型番1', '型番2']] = ...:extract()が複数の列(DataFrame)を返すため、新しい列名のリストに代入することで、それぞれの抽出結果が対応する列に格納されます。 -
マッチしない行(例: 4行目の商品コード列の要素)はNaNになります。
str.extract()のその他の活用例
オプションのグループ (?) の活用
正規表現のパターンで、特定の情報が存在しない場合でもエラーにせず、NaNとして扱いたい場合に便利です。
df_optional = pd.DataFrame({
'商品名': ['PC (Core i7)', 'モニター', 'スマホ (Snapdragon 888)']
})
# CPU情報を抽出 (存在しない場合はNaN)
# 正規表現: \((\w+ \w+)\)? -> 括弧内の単語と単語の組み合わせを抽出
df_optional['CPU'] = df_optional['商品名'].str.extract(r'\((.+?)\)')
print("\nCPU情報を抽出後 (オプショングループ):\n", df_optional)
解説:
r’\((.+?)\)’は、括弧内の任意の文字列を非貪欲にマッチさせ、抽出します。モニターのように括弧がない場合はNaNが格納されます。
名前付きグループ (?P<name>) の活用
抽出する列に直接名前を付けたい場合に便利です。
# 名前付きグループで「年月」と「イベント名」を抽出
df_logs = pd.DataFrame({'ログ': ['2023-01: Login_Success', '2023-02: Logout_Failure']})
df_logs[['年月', 'イベント']] = df_logs['ログ'].str.extract(r'(?P<年月>\d{4}-\d{2}): (?P<イベント>.+)')
print("\n名前付きグループで抽出後:\n", df_logs)
解説:
(?P<年月>…)のように記述することで、抽出される列に直接’年月’という名前が付けられ、コードの可読性が向上します。
正規表現の注意点とヒント
-
エスケープ: 正規表現の特殊文字(
.,*,+,?,|,(,),[,],{,},^,$,\) をリテラルな文字としてマッチさせたい場合は、その前にバックスラッシュ\を置いてエスケープする必要があります(例:\.でドット自体にマッチ)。rプレフィックス(Raw String)を使うと、Pythonの文字列エスケープを考慮せずに正規表現を書けるため推奨されます。 -
貪欲マッチ vs. 非貪欲マッチ:
.*(任意の文字が0回以上繰り返す)は「貪欲マッチ」で、できるだけ長くマッチしようとします。.*?(非貪欲マッチ)とすると、できるだけ短くマッチしようとします。状況に応じて使い分けましょう。 -
テストツール: 複雑な正規表現を書く際は、Regex101.comのようなオンライン正規表現テストツールを使うと、リアルタイムでマッチ結果を確認でき、デバッグに非常に役立ちます。
まとめ
Pandasのstr.extract()メソッドは、正規表現の強力なパターンマッチング能力と組み合わさることで、DataFrameのテキストデータから必要な情報を効率的に抽出して新たな列を生成するための不可欠なツールです。単一または複数の情報を同時に抽出する能力、オプションのグループや名前付きグループの活用は、データクレンジング、特徴量エンジニアリング、そして非構造化データの分析においてその真価を発揮します。正規表現の基本を理解し、str.extract()を使いこなすことで、あなたのデータ分析の幅が大きく広がるでしょう。

