404 Not Found

404 Not Found


nginx

文字列操作【Pandas .str アクセサ完全ガイド】

実際のデータに含まれるテキストは、決してクリーンではありません。余分な空白、大文字・小文字の不統一、特殊文字、混在したフォーマットなど、さまざまな問題があります。Pandas の .str アクセサは、文字列操作にベクトル化をもたらします。1行のコードでテキストの列全体をクリーニングでき、Python のループと比べて最大100倍も高速です。本セクションでは、最もよく使われる文字列メソッドを解説し、チェーン処理によるクリーニングパイプラインの構築方法を示します。

⚠️ 注意: 以下のコードを実行するには、ローカルの Python 環境が必要です。

1. 学習内容



2. キャロルのユーザー入力クリーニング

(1) 問題:ユーザー入力は形式がバラバラ

キャロルが集めたユーザーデータは散々な状態です。

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['  alice  ', 'BOB', 'Charlie!', '  carol  ', 'DaVid123'],
    'email': ['alice@EXAMPLE.com', 'bob@company.ORG', 'charlie@uni.edu',
              'CAROL@example.COM', 'david@test.net'],
    'phone': ['555-0100', '(555) 0200', '555.0300', '+1-555-0400', '5550500']
})
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

(2) 解決策:.str によるチェーンクリーニング

▶ サンプル:チェーンによるテキストクリーニング(難易度 ⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['  alice  ', 'BOB', 'Charlie!', '  carol  ', 'DaVid123'],
    'email': ['alice@EXAMPLE.com', 'bob@company.ORG', 'charlie@uni.edu',
              'CAROL@example.COM', 'david@test.net']
})

# .str メソッドをチェーン:strip → replace → title
df['name_clean'] = (df['name']
    .str.strip()
    .str.replace(r'[^a-zA-Z ]', '', regex=True)
    .str.title()
)
print(df[['name', 'name_clean']])
#          name name_clean
# 0    alice        Alice
# 1         BOB        Bob
# 2   Charlie!    Charlie
# 3     carol        Carol
# 4   DaVid123       David

# メールアドレスのドメインを小文字化
df['email_clean'] = df['email'].str.lower()
print(df['email_clean'])
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。


3. .str アクセサ

(1) .str と Python の str の違い

機能 Python の str Pandas の .str
操作対象 単一の文字列 列全体(ベクトル化)
NaN の扱い エラーが発生 自動的にスキップ(NaN を返す)
チェーン処理 非対応 ✅ 連続呼び出しが可能
パフォーマンス ループ → 遅い ベクトル化 → 高速

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: 基本的な .str メソッド(難易度 ⭐)

PYTHON
import pandas as pd

s = pd.Series(['Hello World', 'pandas', 'DATA SCIENCE', None, 'python'])

# 大文字・小文字の変換
print(s.str.lower())    # hello world, pandas, data science, NaN, python
print(s.str.upper())    # HELLO WORLD, PANDAS, DATA SCIENCE, NaN, PYTHON
print(s.str.title())    # Hello World, Pandas, Data Science, NaN, Python
print(s.str.capitalize())  # Hello world, Pandas, Data science, NaN, Python

# 空白の除去
s2 = pd.Series(['  hello  ', '\tworld\n', '  pandas  '])
print(s2.str.strip())    # hello, world, pandas
print(s2.str.lstrip())   # hello  , world\n, pandas  
print(s2.str.rstrip())   #   hello, \tworld,   pandas

# 文字列の長さ
print(s.str.len())       # 11, 6, 12, NaN, 6
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。


4. replace / contains / match

(1) replace

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: replace による文字列の置換(難易度 ⭐⭐)

PYTHON
import pandas as pd

s = pd.Series(['price: $100', 'price: $200', 'cost: €50'])

# 単純な置換
print(s.str.replace('$', 'USD'))
# price: USD100, price: USD200, cost: €50

# 正規表現による置換
print(s.str.replace(r'[\$€]', '', regex=True))
# price: 100, price: 200, cost: 50

# 複数のパターンを置換
phones = pd.Series(['555-0100', '(555) 0200', '555.0300'])
clean = phones.str.replace(r'[^0-9]', '', regex=True)
print(clean)  # 5550100, 5550200, 5550300
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

(2) contains / startswith / endswith

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: 条件による文字列のフィルタリング(難易度 ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice Johnson', 'Bob Smith', 'Charlie Brown', 'Carol White'],
    'email': ['alice@example.com', 'bob@company.org', 'charlie@uni.edu', 'carol@test.net']
})

# 部分文字列を含むか
has_com = df[df['email'].str.contains('.com')]
print(has_com['name'])  # Alice Johnson

# startswith / endswith
starts_with_a = df[df['name'].str.startswith('A')]
print(starts_with_a)

edu_email = df[df['email'].str.endswith('.edu')]
print(edu_email['name'])  # Charlie Brown

# 正規表現による contains — org または edu ドメインを検索
org_or_edu = df[df['email'].str.contains(r'\.(org|edu)$', regex=True)]
print(org_or_edu[['name', 'email']])
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

(3) contains と match の違い

メソッド マッチ位置 正規表現
contains 文字列内の任意の場所
match 先頭から
startswith 先頭から ❌(プレーンな文字列のみ)
endswith 末尾から ❌(プレーンな文字列のみ)


5. split / extract

(1) split

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: split による文字列の分割(難易度 ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice Johnson', 'Bob Smith', 'Charlie Brown'],
    'email': ['alice@example.com', 'bob@company.org', 'charlie@uni.edu']
})

# リストに分割
print(df['name'].str.split(' '))
# 0    [Alice, Johnson]
# 1    [Bob, Smith]
# 2    [Charlie, Brown]

# 個別の列に分割
name_split = df['name'].str.split(' ', expand=True)
print(name_split)
#         0        1
# 0   Alice  Johnson
# 1     Bob    Smith
# 2 Charlie    Brown

# 分割して最初の部分だけを取得
df['first_name'] = df['name'].str.split(' ').str[0]
print(df['first_name'])

# メールアドレスを分割してドメインを取得
df['domain'] = df['email'].str.split('@').str[1]
print(df['domain'])
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

(2) 正規表現を使った extract

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: extract によるパターンの抽出(難易度 ⭐⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'contact': [
        'Alice <alice@example.com>',
        'Bob <bob@company.org>',
        'Charlie (555-0100)',
        'Carol <carol@test.net>'
    ]
})

# 正規表現のグループでメールアドレスを抽出
df['email'] = df['contact'].str.extract(r'<(.+?)>')
print(df[['contact', 'email']])
#                   contact             email
# 0  Alice <alice@example.com>  alice@example.com
# 1      Bob <bob@company.org>    bob@company.org
# 2     Charlie (555-0100)                NaN
# 3    Carol <carol@test.net>    carol@test.net

# 複数のグループを抽出
df2 = pd.DataFrame({
    'email': ['alice@example.com', 'bob@company.org']
})
parts = df2['email'].str.extract(r'(.+?)@(.+)')
print(parts)
#        0             1
# 0  alice  example.com
# 1    bob   company.org

# すべてのマッチを抽出
colors = pd.Series(['red,blue,green', 'yellow,pink'])
print(colors.str.extractall(r'(\w+)'))
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。


6. その他のよく使うメソッド

(1) クイックリファレンス

メソッド 目的
len() 文字列の長さ s.str.len()
count() 部分文字列の出現回数 s.str.count('a')
find() 部分文字列の位置 s.str.find('bc')
isdigit() すべて数字か? s.str.isdigit()
isalpha() すべてアルファベットか? s.str.isalpha()
join() 区切り文字で結合 s.str.join(',')
pad() 固定幅にパディング s.str.pad(10, fillchar='0')
repeat() 文字列の繰り返し s.str.repeat(3)
slice() スライス s.str.slice(0, 5)

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: pad/slice/zfill(難易度 ⭐)

PYTHON
import pandas as pd

ids = pd.Series(['1', '23', '456', '7890'])

# 0でパディングして4桁にする
print(ids.str.zfill(4))
# 0    0001
# 1    0023
# 2    0456
# 3    7890

# 先頭2文字をスライス
codes = pd.Series(['US-001', 'UK-002', 'JP-003'])
print(codes.str.slice(0, 2))  # US, UK, JP
print(codes.str[:2])           # 同上、Python のスライス構文
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。


7. 総合例:ユーザーデータのテキストクリーニングパイプライン

(5) ▶ テキストクリーニングのワークフロー

100%
graph TB
    A[生テキスト] --> B[strip:空白を除去]
    B --> C[lower / upper:大文字・小文字を正規化]
    C --> D[replace:特殊文字を除去]
    D --> E[split / extract:情報を抽出]
    E --> F[title:出力を整える]
    F --> G[クリーンなテキスト]
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

▶ サンプル

TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

: エンドツーエンドのテキストクリーニング(難易度 ⭐⭐⭐)

PYTHON
import pandas as pd

# ============================================
# 総合例:ユーザーデータに対する
# テキストクリーニングパイプライン
# ============================================

# 1. 整形前のバラバラなユーザーデータ
df = pd.DataFrame({
    'raw_name': ['  ALICE johnson  ', 'bob   SMITH', '  CHARLIE! brown  ', 'CAROL white123'],
    'raw_email': ['ALICE@Example.COM', 'bob@company.ORG', 'charlie@uni.EDU', 'CAROL@TEST.NET'],
    'raw_phone': ['555-0100', '(555) 0200', '555.0300 ext 42', '+1-555-0400'],
    'raw_zip': ['0123', '12345', '  90210  ', '10001-2345']
})

# 2. 名前のクリーニング:strip → 特殊文字を除去 → タイトルケース
df['name'] = (df['raw_name']
    .str.strip()
    .str.replace(r'[^a-zA-Z\s]', '', regex=True)
    .str.replace(r'\s+', ' ', regex=True)  # 連続する空白を1つにまとめる
    .str.title()
)

# 3. メールアドレスのクリーニング:小文字化
df['email'] = df['raw_email'].str.lower()

# 4. 電話番号のクリーニング:数字だけを残す
df['phone_digits'] = df['raw_phone'].str.replace(r'[^0-9]', '', regex=True)
df['phone_formatted'] = df['phone_digits'].str.slice(0, 3) + '-' + df['phone_digits'].str.slice(3, 7)

# 5. 郵便番号:5桁のコードを抽出
df['zip5'] = df['raw_zip'].str.strip().str.extract(r'(\d{5})')

# 6. メールアドレスのドメイン
df['domain'] = df['email'].str.split('@').str[1]

# 7. クリーニング結果を表示
print("=== Cleaned Data ===")
print(df[['name', 'email', 'phone_formatted', 'zip5', 'domain']])
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていません。ローカルにインストール(`pip install pandas`)してから試してください。実際の値は pandas のバージョンによって若干異なる場合があります。

❓ よくある質問

Q .str と Python の str の違いは何ですか?
A Python の str メソッドは単一の文字列を操作しますが、.str アクセサは列全体を操作します(ベクトル化)。.str アクセサは NaN の値を自動的にスキップし(NaN を返す)ますが、Python の str は NaN に対してエラーを発生させます。.str アクセサはメソッドチェーン(s.str.strip().str.lower())に対応していますが、Python の str は対応していません。パフォーマンスの面では、.str はループより10〜100倍高速です。
Q NaN の値はどのように扱われますか?
A .str メソッドは NaN を自動的にスキップします。入力が NaN の場合、出力も NaN になります。欠損値を手動でチェックする必要はありません。これは、.str が apply + Python の str を使うより便利な理由の1つです。なお、contains/match は NaN の値に対して NaN ではなく False を返すため、フィルタリングの際は注意してください。
Q extract は何を返しますか?
A extract はデータフレームを返します。正規表現のグループごとに1列となります。グループが1つなら1列のデータフレーム、複数のグループなら複数の列になります。extractall はすべてのマッチを返します(MultiIndex 付き)。注意:マッチしない行は NaN を返します。Series が必要な場合は、.str.extract(...)[0] を使ってください。
Q contains と match の違いは何ですか?
A contains は文字列内の任意の場所にマッチします(例:'abc' が 'b' を contains → True)。match は文字列の先頭からのみマッチします(例:'abc' が 'b' に match → False)。startswith/endswith はプレーンな文字列の比較です(正規表現には非対応)。正規表現が必要なときは contains/match を、単純なテキストチェックのときは startswith/endswith を使ってください。
Q StringDtype の利点は何ですか?
A デフォルトでは、文字列の列は object 型(Python オブジェクト)を使用し、各値が個別の str インスタンスになります。StringDtype(df['col'].astype('string'))は Pandas 専用の文字列型で、欠損値に pd.NA を使用し、メモリ効率が高く、より一貫した .str の動作を提供します。Pandas 2.x では、文字列データには object より StringDtype が推奨されています。
Q str.replace と df.replace の違いは何ですか?
A str.replace は文字列の列のみを操作し、正規表現に対応し(regex=True)、要素ごとに置換します。df.replace はデータフレーム全体を操作し、任意の型の値を置換でき、正規表現にも対応します。文字列の置換には str.replace(意味が明確)を、列をまたぐ置換には df.replace を使うのがよいでしょう。
Q 電話番号から数字を抽出するにはどうすればよいですか?
A s.str.replace(r'[^0-9]', '', regex=True) を使うと、数字以外の文字をすべて除去できます。あるいは extract を使い、s.str.extract(r'(\d{3})[-.)\s]*(\d{3})[-.)\s]*(\d{4})') で市外局番、プレフィックス、加入者番号をそれぞれ取得することもできます。正規表現はテキスト抽出の中核となるツールです。

📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):余分な空白と大文字・小文字の不統一がある名前の Series を作成してください。.str.strip().str.title() でクリーニングし、クリーニング後の名前のうち 'A' で始まるものがいくつあるか数えてください。
  2. 応用(難易度 ⭐⭐):形式が混在した電話番号の Series を作成してください。replace + 正規表現で数字だけを抽出し、zfill で10文字に整形してください。
  3. 挑戦(難易度 ⭐⭐⭐):ユーザー登録データ(name/email/phone/zip のすべてに書式の問題があるもの)を模擬的に作成してください。5段階のチェーンクリーニングパイプライン(各段階で .str メソッドを1つ使用)を構築し、最終的なクリーンなテーブルを出力してください。

← 前へ:データの再整形とピボット · 次へ:日付と時刻 →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%