read_csvで空白や桁ズレが原因で数値変換できない

Prep

read_csvで空白や桁ズレが原因で数値変換できない

作成日: 最終更新: 読了時間: 1 分

pandas.read_csv() で読み込んだ列を数値に変換しようとすると

ValueError: could not convert string to float: ' 1,234 '

ValueError: invalid literal for int() with base 10: '001 234'

といったエラーで処理が止まることがあります。これは 列の中に余計な空白・全角スペース・桁ズレが含まれている ためです。


解決法 1: 読み込み時に空白を自動でトリムする #

import pandas as pd

df = pd.read_csv("sales.csv", skipinitialspace=True)

skipinitialspace=True を指定すると、区切り文字の直後にある半角スペースを自動で削除してくれます。
ただし全角スペースやタブには効かないため、別途 .str.strip() を併用します。


解決法 2: 文字列を明示的にクレンジングしてから数値化する #

df = pd.read_csv("sales.csv", dtype=str)  # いったん文字列で統一

df["amount"] = (
    df["amount"]
    .str.replace(r"[\\s,]", "", regex=True)  # 空白とカンマを除去
    .astype("Int64")                         # 欠損にも対応できる pandas の Int64
)

dtype=str で文字列として読み込み、不要な空白やカンマを正規表現で除去してから数値化すると安全です。
桁ズレやタブが混ざる帳票でも柔軟に処理できます。


解決法 3: 固定長レイアウトなら read_fwf を使う #

帳票によっては CSV ではなく 固定長 (Fixed Width) のテキストが渡されることがあります。
この場合は read_fwf に切り替えると列境界を位置で指定できます。

df = pd.read_fwf(
    "report.txt",
    widths=[8, 12, 10],
    names=["customer_id", "amount", "created_at"],
)

解決法 4: 列単位でクリーニング関数を適用する #

def clean_amount(value: str) -> float | None:
    value = value.replace("\u3000", "").replace(",", "").strip()  # 全角スペース対策
    return float(value) if value else None

df = pd.read_csv("sales.csv", converters={"amount": clean_amount})

converters に関数を渡すと、読み込み段階で値を整形できます。
全角スペース (\u3000) や制御文字を取り除いてしまいましょう。


チェックリスト #

  1. 半角スペースだけでなく 全角スペース やタブが混じっていないか
  2. 見た目の桁区切りとして カンマ が含まれていないか
  3. 固定長形式なら read_fwf を検討したか
  4. 変換できない値があったとき errors='coerce' を使うか検討したか
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")

参考 #