【Pandasテクニック】文字列を含む行を効率的に抽出する方法(完全一致・部分一致)
データ分析の際、DataFrameの中から特定のキーワードやパターンを含む行だけを選び出したい、という場面は頻繁にあります。顧客データから特定の地域の人を抽出したり、商品リストから特定の種類の商品をフィルタリングしたりと、その用途は多岐にわたります。Pandasを使えば、**文字列の「完全一致」や「部分一致」**に基づいて、効率的に目的の行を抽出することができます。この記事では、これらの文字列抽出テクニックを、短いサンプルコードと丁寧な解説を交えてご紹介します。
なぜ文字列を含む行を抽出するのか?
文字列を含む行を抽出する主な理由は以下の通りです。
-
データフィルタリング: 大規模なデータセットから、特定の条件に合致するサブセットを作成します。
-
特定のデータの分析: 抽出したデータに対してのみ、統計分析や可視化を行います。
-
データクレンジング: 特定のパターンを持つエラーデータや不要な行を特定し、処理します。
-
特徴量エンジニアリング: 既存の文字列データから、新しいカテゴリやフラグを作成する前段階として利用します。
完全一致で文字列を含む行を抽出する
DataFrameの特定の列の値が、指定した文字列と完全に一致する行を抽出する方法です。これは最も基本的な文字列フィルタリングのテクニックです。
比較演算子 == を使う
最もシンプルで直感的な方法です。
import pandas as pd
# サンプルDataFrameの作成
df = pd.DataFrame({
'商品名': ['りんご', 'みかん', 'バナナ', 'りんご'],
'色': ['赤', 'オレンジ', '黄', '青'],
'価格': [100, 120, 80, 110]
})
print("オリジナルDataFrame:\n", df)
# '商品名'が'りんご'と完全に一致する行を抽出
df_filtered_exact = df[df['商品名'] == 'りんご']
print("\n'商品名'が'りんご'に完全一致する行:\n", df_filtered_exact)
解説:
df[‘商品名’] == ‘りんご’は、’商品名’列の各要素が’りんご’と一致するかどうかを判定し、True/FalseのブールSeriesを生成します。このSeriesを使ってDataFrameをフィルタリングします。
複数の文字列に完全一致する行を抽出する
複数の特定の文字列のいずれかに一致する行を抽出したい場合は、isin()メソッドが便利です。
# '色'が'赤'または'黄'に完全一致する行を抽出
df_filtered_isin = df[df['色'].isin(['赤', '黄'])]
print("\n'色'が'赤'または'黄'に完全一致する行:\n", df_filtered_isin)
解説:
df[‘色’].isin([‘赤’, ‘黄’])は、’色’列の要素がリスト[‘赤’, ‘黄’]のいずれかに含まれる場合にTrueを返します。
部分一致で文字列を含む行を抽出する
指定した文字列が、列の要素の中に一部でも含まれていれば抽出したい場合に使う方法です。これはより柔軟なフィルタリングを可能にします。
str.contains()メソッドを使う
str.contains()は、Series(文字列型の列)に対して適用し、指定したパターンが文字列に含まれているかをブール値で返します。正規表現も利用可能です。
# '商品名'に'んご'が含まれる行を抽出
df_filtered_contains = df[df['商品名'].str.contains('んご')]
print("\n'商品名'に'んご'が部分一致する行:\n", df_filtered_contains)
解説:
df[‘商品名’].str.contains(‘んご’)は、’商品名’列の各文字列に’んご’という部分文字列が含まれるかを判定します。’りんご’がこれに該当します。
大文字・小文字を区別しない検索
デフォルトでは大文字・小文字を区別しますが、case=Falseを設定すると区別しなくなります。
df_case = pd.DataFrame({'Product': ['Apple', 'apple', 'Orange']})
# 'Product'に'apple'が部分一致する行を抽出 (大文字・小文字を区別しない)
df_filtered_ignore_case = df_case[df_case['Product'].str.contains('apple', case=False)]
print("\n大文字・小文字を区別せず'apple'に部分一致する行:\n", df_filtered_ignore_case)
正規表現を使う
str.contains()は正規表現をサポートしているため、複雑なパターンマッチングも可能です。
# '商品名'が'り'で始まる行を抽出(正規表現: ^り)
df_filtered_regex = df[df['商品名'].str.contains('^り', regex=True)]
print("\n正規表現で'り'で始まる商品名を含む行:\n", df_filtered_regex)
解説:
^りは正規表現で「りで始まる文字列」を意味します。regex=Trueを明示的に指定することで、正規表現としてパターンが解釈されます。
str.startswith() / str.endswith() メソッドを使う
特定の文字列で始まる、または終わる行を抽出したい場合に便利です。
# '商品名'が'み'で始まる行を抽出
df_filtered_starts = df[df['商品名'].str.startswith('み')]
print("\n'商品名'が'み'で始まる行:\n", df_filtered_starts)
# '商品名'が'な'で終わる行を抽出
df_filtered_ends = df[df['商品名'].str.endswith('な')]
print("\n'商品名'が'な'で終わる行:\n", df_filtered_ends)
欠損値(NaN)の扱い
文字列列に欠損値(NaN)が含まれている場合、strアクセサメソッド(str.contains()など)はデフォルトでNaNをFalseとして扱います。つまり、欠損値を含む行は抽出されません。
もしNaNを含む行も抽出対象にしたい場合は、別途条件を追加する必要があります。
import numpy as np
df_nan_str = pd.DataFrame({'Text': ['hello', np.nan, 'world']})
# 'o'を含む行を抽出 (NaNは含まれない)
filtered_nan_default = df_nan_str[df_nan_str['Text'].str.contains('o', na=False)] # na=Falseはデフォルト
print("\n'o'を含む行 (NaNは無視):\n", filtered_nan_default)
# 'o'を含むか、NaNである行を抽出
filtered_nan_include = df_nan_str[df_nan_str['Text'].str.contains('o', na=False) | df_nan_str['Text'].isnull()]
print("\n'o'を含むか、NaNである行:\n", filtered_nan_include)
解説:
-
na=Falseはstr.contains()のデフォルトで、NaNをFalseとして扱います。 -
NaNを含む行も対象にしたい場合は、
| df_nan_str['Text'].isnull()のように、NaNであるという条件をORで結合します。
まとめ
Pandasで特定の文字列を含む行を抽出する方法は、データ分析において非常に重要なスキルです。完全一致には==演算子やisin()、部分一致にはstr.contains()、str.startswith()、str.endswith()メソッドを使い分けます。また、正規表現を活用することで、さらに複雑なパターンに基づいた抽出も可能になります。これらのテクニックをマスターし、あなたのデータ処理をより効率的かつ柔軟に進めましょう。
