pandas str.strip()の使い方|文字列・列名の前後空白を削除する方法

東京を指定したのに一部の行が出てこない。同じ地域が別々に集計される。正しい列名なのにKeyErrorになる——原因は、CSVやExcelに紛れ込んだ見えない空白かもしれません。pandasでは、文字列が入った列にstr.strip()を使うと前後の空白を削除できます。

df["地域"] = df["地域"].str.strip()

左側だけならstr.lstrip()、右側だけならstr.rstrip()、列名の前後空白ならdf.columns.str.strip()を使います。この記事では、空白を見つけるところから、削除後に抽出・集計が正しくできることを確認するところまで、Google Colabで試せる例で解説します。

この記事でわかること

  • df["列名"].str.strip()で値の前後空白を削除する方法
  • str.strip()str.lstrip()str.rstrip()の違い
  • df.columns.str.strip()で列名の空白を削除する方法
  • 半角スペース・全角スペース・タブ・改行・NaNの注意点
  • str.strip()str.replace()replace()rename()の使い分け
  • unique()value_counts()で修正前後を確認する方法

先に判断基準:値の両端ならstr.strip()、左端だけならstr.lstrip()、右端だけならstr.rstrip()、列名の両端ならdf.columns.str.strip()です。文字列の途中にある空白や、別の値への置換は目的が異なります。

Pandas DataFrame入門シリーズでの位置づけ

空白の除去は、データを読み込んで内容を確認したあと、抽出・集計・結合へ進む前に行う前処理です。

CSV・Excel読込 → 値と型の確認 → 前後空白の除去 → 表記ゆれの修正 → 抽出・集計・結合

Google ColabへのCSV読込はこちらの記事、Excelの読込はread_excel()の記事で詳しく解説しています。

見えない空白が抽出・集計を狂わせる

次の売上データには、地域名の前後に半角スペースや全角スペースが混ざっています。表では違いが分かるよう、半角スペースを、全角スペースをとして示します。実際のDataFrameでは、これらは見えにくい文字です。

実際の値 見える表記 売上
0 東京 東京 1200
1 東京 ␠東京 1800
2 東京 東京␠ 1500
3  東京  □東京□ 900
4 大阪 大阪 1100
5 NaN 欠損値 700

まずは追加ファイル不要のサンプルデータを作り、空白を除去する前の状態を確認します。repr()を使うと、半角スペースは引用符の内側に見え、全角スペースも位置を確認しやすくなります。

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "地域": ["東京", " 東京", "東京 ", " 東京 ", "大阪", np.nan],
    "商品": ["商品A", "商品B", "商品C", "商品D", "商品E", "商品F"],
    "売上": [1200, 1800, 1500, 900, 1100, 700]
})

print("repr()で確認:")
print(df["地域"].map(repr).to_list())

print("\n空白除去前の件数:")
print(df["地域"].value_counts(dropna=False))

print("\n'東京'と完全一致する行:")
display(df[df["地域"] == "東京"] )
repr()で確認:
["'東京'", "' 東京'", "'東京 '", "'\\u3000東京\\u3000'", "'大阪'", 'nan']

空白除去前の件数:
count
東京1
東京1
東京 1
 東京 1
大阪1
nan1
'東京'と完全一致する行:
地域商品売上
0東京商品A1200

東京東京東京 東京 は、pandasでは別の文字列です。そのため、空白除去前のvalue_counts()では別々に数えられ、== "東京"では空白のない1行しか抽出されません。

値の種類を詳しく調べる方法はunique()・nunique()の記事、件数の確認方法はvalue_counts()の記事も参考にしてください。

str.strip()で文字列の前後空白を削除する

pandasでは、DataFrameの1列分を**Series(シリーズ)**と呼びます。列に入っている文字列をまとめて処理するため、.strを付けてdf["地域"].str.strip()と書きます。

str.strip()は、前後の半角スペース・全角スペース・タブ・改行などを取り除きます。文字列の途中にある空白は残ります。画面では見えない特殊な文字が残る場合もあるため、実データでは処理前後を確認しましょう。

# 処理前の値を残し、比較できるようにする
df["地域_処理前"] = df["地域"]

# 結果を代入して、地域列を更新する
df["地域"] = df["地域"].str.strip()

comparison = df[["地域_処理前", "地域"]].copy()
comparison["処理前_repr"] = comparison["地域_処理前"].map(repr)
comparison["処理後_repr"] = comparison["地域"].map(repr)
display(comparison[["処理前_repr", "処理後_repr"]])

print("空白除去後の件数:")
print(df["地域"].value_counts(dropna=False))

print("\n空白除去後に'東京'と一致する行:")
display(df[df["地域"] == "東京"][["地域", "商品", "売上"]])
処理前_repr処理後_repr
0‘東京’‘東京’
1‘ 東京’‘東京’
2‘東京 ‘‘東京’
3‘\u3000東京\u3000’‘東京’
4‘大阪’‘大阪’
5nannan
空白除去後の件数:
count
東京4
大阪1
nan1
空白除去後に'東京'と一致する行:
地域商品売上
0東京商品A1200
1東京商品B1800
2東京商品C1500
3東京商品D900

処理後は、空白違いで分かれていた4つの値がすべて東京になります。その結果、value_counts()では東京が4件にまとまり、条件抽出でも4行を取得できます。空白除去によって別々だったカテゴリが統合されるため、集計件数が変わるのは正常です。

処理前 処理後
東京 東京
␠東京 東京
東京␠ 東京
□東京□ 東京
大阪 大阪
NaN NaN

NaNは空文字列ではなく欠損値です。str.strip()を使っても欠損値のまま保たれます。欠損値を埋めたい場合は、空白除去とは分けてfillna()を検討します。

重要df["地域"].str.strip()を実行しただけでは、元の列は変わりません。更新するにはdf["地域"] = ...のように結果を代入します。

str.strip()・str.lstrip()・str.rstrip()の違い

同じ文字列を使うと、どちら側の空白が削除されるかを比較できます。

目的 pandasでの書き方 結果のイメージ
前後を削除 s.str.strip() ␠東京␠東京
左側だけ削除 s.str.lstrip() ␠東京␠東京␠
右側だけ削除 s.str.rstrip() ␠東京␠␠東京
s = pd.Series([" 東京 ", " 大阪 ", "商品 A", "\t名古屋\n"])

result = pd.DataFrame({
    "元の値": s.map(repr),
    "strip": s.str.strip().map(repr),
    "lstrip": s.str.lstrip().map(repr),
    "rstrip": s.str.rstrip().map(repr)
})
display(result)
元の値striplstriprstrip
0‘ 東京 ‘‘東京’‘東京 ‘‘ 東京’
1‘\u3000大阪\u3000’‘大阪’‘大阪\u3000’‘\u3000大阪’
2‘商品 A’‘商品 A’‘商品 A’‘商品 A’
3‘\t名古屋\n’‘名古屋’‘名古屋\n’‘\t名古屋’

strip(chars)は指定した語句を丸ごと削除する機能ではない

strip("abc")は、abcという並びを探して削除する機能ではありません。文字列の両端から、abcのどれかに当たる文字を1文字ずつ取り除きます。それ以外の文字に当たると処理が止まり、文字列の途中にある文字は削除されません。

次の例では、両端にあるHelo!は削除されますが、途中のPythonに含まれるoは残ります。

sample = pd.Series(["Helloooo! Python!"])
print(sample.str.strip("Helo!").iloc[0])
# 結果は ' Python'。途中にあるPythonのoは削除されない
 Python

補足:文字以外の値が混ざる列に注意する

1つの列に文字列と数値が混ざっている場合は注意が必要です。.str.strip()を使うと、数値やTrueFalseは欠損値になります。元からあるNaNも欠損値のままです。実行前に、対象列へ文字列だけが入っているか確認しましょう。

mixed = pd.Series([" 東京 ", 100, True, np.nan], dtype="object")
mixed_result = pd.DataFrame({
    "処理前": mixed.map(repr),
    "処理後": mixed.str.strip().map(repr)
})
display(mixed_result)
処理前処理後
0‘ 東京 ‘‘東京’
1100nan
2Truenan
3nannan

商品 Aのような文字列途中の空白は、どのstrip系メソッドでも残ります。途中の空白を削除・置換したい場合はstr.replace()の役割です。

空白除去では引数を省略する使い方を基本にすると安全です。

列名の前後空白はdf.columns.str.strip()で削除する

CSVやExcelの見出しに空白が入っていると、df["売上"]と指定しても、実際の列名が" 売上"ならKeyErrorになります。列のではなく列名を整える場合は、df.columnsに対してstr.strip()を使います。

変更前の列名 変更後の列名
商品名 商品名
␠売上 売上
地域␠ 地域
df_columns = pd.DataFrame(
    [["商品A", 1200, "東京"], ["商品B", 1100, "大阪"]],
    columns=["商品名", " 売上", "地域 "],
)

print("変更前:", [repr(col) for col in df_columns.columns])
df_columns.columns = df_columns.columns.str.strip()
print("変更後:", [repr(col) for col in df_columns.columns])

# 空白除去後は、空白なしの列名で選択できる
display(df_columns[["商品名", "売上", "地域"]])
変更前: ["'商品名'", "' 売上'", "'地域 '"]
変更後: ["'商品名'", "'売上'", "'地域'"]
商品名売上地域
0商品A1200東京
1商品B1100大阪

df.columns.str.strip()は列名の前後空白を取る処理です。売上金額売上へ変えるように、列名そのものを別名へ変更したい場合はrename()の記事を参照してください。

strip・replace・renameは目的で使い分ける

空白や表記ゆれを直す方法は似て見えますが、処理する場所と目的が違います。

目的 使う方法 主な対象
値の前後空白を削除 s.str.strip() 1列の各文字列 ␠東京␠東京
値の左端だけ削除 s.str.lstrip() 1列の各文字列 ␠東京␠東京␠
値の右端だけ削除 s.str.rstrip() 1列の各文字列 ␠東京␠␠東京
文字列の一部を置換 s.str.replace() 各文字列の一部分 商品 A商品A
値全体を別の値へ置換 s.replace() SeriesまたはDataFrameの値 東京都東京
列名の前後空白を削除 df.columns.str.strip() 列名 ␠売上売上
列名を別名へ変更 df.rename() 列名・行ラベル 売上金額売上

Pythonの単一文字列textならtext.strip()、pandasの列df["地域"]ならdf["地域"].str.strip()です。値全体の置換や辞書を使った表記統一はpandas replace()の記事で詳しく扱っています。

よくあるミスと注意点

1. 結果を代入せず、元の列も変わったと思う

str.strip()は、空白を削除した新しい結果を返します。元の列は自動では変わらないため、df["地域"] = ...のように対象列へ戻します。

2. 文字列の途中にある空白まで消えると思う

strip()が対象にするのは両端です。商品 Aの中央の空白を変えたい場合はstr.replace()などを検討します。ただし、氏名や住所など、途中の空白に意味があるデータもあるため、一律に消してよいか確認が必要です。

3. NaNと空文字列を同じものとして扱う

NaNは欠損値、""は長さ0の文字列、" "は空白だけの文字列です。空白だけの文字列はstrip()後に""になりますが、自動でNaNにはなりません。

4. 混在列を安易にastype(str)へ変換する

数値や欠損値が混ざる列をastype(str)にすると、欠損値まで文字列の"nan"になる場合があります。まずdtypesで型を確認し、必要な列だけ処理しましょう。型変換はastype()の記事で詳しく解説しています。

5. 全角スペースを見落とす

日本語データには全角スペースが混ざることがあります。引数なしのstr.strip()では一般的な全角スペースも両端から除去できますが、repr()unique()value_counts()で処理前後を確認する習慣が大切です。

前処理の流れでstr.strip()を使うタイミング

実際の分析では、次の順番にすると空白による見落としを減らせます。

  1. CSVやExcelを読み込む
  2. head()dtypesunique()value_counts()で列と値を確認する
  3. 文字列値はSeries.str.strip()、列名はdf.columns.str.strip()で前後空白を除去する
  4. unique()value_counts()を再実行し、カテゴリが正しく統合されたか確認する
  5. 必要ならreplace()で他の表記ゆれを統一する
  6. 条件抽出、groupby()merge()、可視化へ進む

空白除去後の部分一致抽出はstr.contains()の記事、集計はgroupby×aggの記事、DataFrameの結合はmergeの記事へ進むと、分析の流れをつなげて学べます。

複数の文字列列をまとめて処理する方法や、正規表現による連続空白の統一、Unicode正規化、大規模データでの速度最適化もあります。ただし、最初は問題のある列を特定し、1列ずつ安全に確認する方法で十分です。

まとめ

  • pandasで文字列の前後空白を削除する基本はSeries.str.strip()
  • 左側だけならstr.lstrip()、右側だけならstr.rstrip()
  • 列名の前後空白はdf.columns.str.strip()で削除する
  • strip()は文字列途中の空白を削除しない
  • NaN、空文字列、空白だけの文字列は別の値として考える
  • 処理結果を代入し、unique()value_counts()で修正後を確認する
  • 空白除去は、データ読込・確認のあと、抽出・集計・結合の前に行う

まずは、見た目が同じ値が別々に集計されていないかを確認してみましょう。前後空白が原因なら、対象の文字列列にstr.strip()を使うことで、その後の抽出や集計を正しく進めやすくなります。

次に読みたい関連記事

▲ ページトップへ戻る

str.strip()は半角スペースと全角スペースの両方を削除できますか?

引数を省略したstr.strip()は、文字列の前後にある一般的な半角スペース・全角スペース・タブ・改行などを削除します。ただし、画面では見えない特殊な文字が残る場合もあるため、repr()unique()で結果を確認してください。

str.strip()とstr.replace()はどう使い分けますか?

前後の空白を取り除くならstr.strip()、文字列の途中を含む特定文字を置換するならstr.replace()です。値全体を別の値へ置換するSeries.replace()DataFrame.replace()とも目的が異なります。

文字列の途中にある空白も削除できますか?

str.strip()では削除できません。途中の空白にはstr.replace()などを使えますが、氏名や住所の空白まで消してよいかを先に確認しましょう。

列名の前後空白をまとめて削除できますか?

はい。df.columns = df.columns.str.strip()で列名の前後空白をまとめて削除できます。列名を別の名前へ変更する場合はrename()を使います。

str.strip()を使ったのに元のDataFrameが変わらないのはなぜですか?

str.strip()は処理後の新しいSeriesを返すためです。df["地域"] = df["地域"].str.strip()のように対象列へ代入してください。

空白を削除したら別々だったカテゴリは同じ値として集計されますか?

はい。東京東京東京がすべて東京になれば、value_counts()groupby()では同じカテゴリとして集計されます。削除後に件数が意図どおりか必ず確認してください。

コメント

タイトルとURLをコピーしました