Python Excel操作 逆引き集 | 読み込み時にカラムの変換関数を使う

Python Python
スポンサーリンク

「読み込んでから直す」じゃなく「読み込む瞬間に直す」

Excelの生データって、だいたいこういう“ちょっとイヤな感じ”が混ざっています。

  • 前後にスペースが付いた文字列(" A001 "
  • 全角・半角が混ざったコード
  • 数字っぽいけど文字列として入っている値
  • 「はい/いいえ」を Y/N にしたい、などの表記ゆれ

普通は「読み込んだあとに df["col"].str.strip() で直す」ことが多いですが、
converters={'col': 関数} を使うと、読み込みの瞬間に変換してから DataFrame に入れることができます。

converters={'col': lambda x: x.strip()} は、
「col 列に入ってくる値は、全部 strip() してから保存してね」という指定です。


基本形:converters={‘col’: lambda x: x.strip()} の挙動

最小コードとイメージ

import pandas as pd

df = pd.read_excel(
    "data.xlsx",
    converters={
        "code": lambda x: x.strip()
    }
)

print(df["code"].head())
Python

ここで起きていることは、こうです。

  1. Excelから1セルずつ値を読む
  2. code 列に入る値は、いったん lambda x: x.strip() に通す
  3. その戻り値を DataFrame に入れる

つまり、「生の値 → 変換関数 → DataFrame」という流れになります。
strip() は文字列の前後の空白を削る関数なので、
" A001 ""A001" のように、きれいな形で入ってきます。


converters と dtype の違いをはっきりさせる

dtype は「型を決める」、converters は「値を加工する」

dtype={"col": str} は、「この列は文字列型として扱ってね」という“型の指定”です。
一方、converters={"col": 関数} は、「この列の値はこう変換してから入れてね」という“変換ロジック”です。

例えば、こういう組み合わせもできます。

df = pd.read_excel(
    "data.xlsx",
    dtype={"code": "string"},
    converters={"code": lambda x: x.strip()}
)
Python

この場合、

  • まずセルの値が lambda x: x.strip() に通される
  • その結果が「文字列型」として DataFrame に入る

というイメージです。

「型を揃えるだけなら dtype」「中身をいじりたいなら converters」と覚えておくと整理しやすいです。


よくある実務パターンで考える

パターン1:前後のスペースを全部消したい(ID・コード系)

Excelの「顧客ID」「商品コード」などに、なぜかスペースが混ざっているパターン。

import pandas as pd

df = pd.read_excel(
    "customers.xlsx",
    converters={
        "CustomerID": lambda x: str(x).strip()
    }
)

print(df["CustomerID"].head())
Python

ここでは、str(x).strip() としているのがポイントです。
空欄や数値が混ざっていても、とりあえず文字列にしてから strip() することで、
" 001 ""001" のようにきれいに揃えられます。

パターン2:「はい/いいえ」を True/False に変換したい

Excel側では「はい」「いいえ」と書いてあるけれど、
Python側ではブール値(True/False)で扱いたい場合。

import pandas as pd

def yes_no_to_bool(x):
    if x in ("はい", "YES", "Yes", "yes"):
        return True
    if x in ("いいえ", "NO", "No", "no"):
        return False
    return None  # よくわからないものは欠損扱い

df = pd.read_excel(
    "survey.xlsx",
    converters={
        "同意": yes_no_to_bool
    }
)

print(df["同意"].head())
print(df["同意"].dtype)
Python

こうしておくと、読み込んだ瞬間から True/False/None の列として扱えます。
後から replace するより、入口で変換してしまった方がスッキリです。

パターン3:数字っぽい文字列を、きれいな数値にしておきたい

「1,234」「 500 」のような文字列を、ちゃんと数値にしておきたい場合。

import pandas as pd

def to_int_or_nan(x):
    if x is None:
        return None
    s = str(x).replace(",", "").strip()
    return int(s) if s.isdigit() else None

df = pd.read_excel(
    "sales.xlsx",
    converters={
        "数量": to_int_or_nan
    }
)

print(df["数量"].head())
print(df["数量"].dtype)
Python

ここでは、"1,234""1234"1234 のように変換しています。
converters を使うと、「Excelの変な書き方」を読み込み時に正規化できるのが強みです。


converters を複数列に使う

複数列を同時に指定する

import pandas as pd

df = pd.read_excel(
    "sales.xlsx",
    converters={
        "CustomerID": lambda x: str(x).strip(),
        "ProductCode": lambda x: str(x).strip(),
        "数量": lambda x: int(str(x).strip()) if str(x).strip().isdigit() else None
    }
)

print(df.head())
Python

列ごとに違う変換ロジックを持たせられるので、
「IDはスペース除去」「数量は数値化」「フラグは True/False」など、
列の性質に合わせた前処理を、読み込み時に埋め込めます。


converters と他の引数の組み合わせ

usecols と一緒に使う

import pandas as pd

df = pd.read_excel(
    "sales.xlsx",
    usecols=["日付", "顧客ID", "数量"],
    converters={
        "顧客ID": lambda x: str(x).strip(),
        "数量": lambda x: int(str(x).strip()) if str(x).strip().isdigit() else None
    }
)

print(df.head())
Python

usecols で列を絞りつつ、残した列にだけ変換関数を適用する、という形です。

parse_dates と一緒に使う

日付列は parse_dates に任せることが多いですが、
「変なフォーマットが混ざっている」場合は、あえて converters で自分で処理することもあります。

import pandas as pd
from datetime import datetime

def parse_weird_date(x):
    try:
        return pd.to_datetime(x, errors="coerce")
    except Exception:
        return None

df = pd.read_excel(
    "weird_dates.xlsx",
    converters={
        "日付": parse_weird_date
    }
)

print(df["日付"].head())
Python

parse_dates でうまくいかないときの“最後の手段”として、
自作パーサーを converters に渡す、というイメージです。


実践テンプレート

テンプレ1:顧客IDのスペースを削り、数量を数値化してから集計

import pandas as pd

def clean_id(x):
    return str(x).strip()

def to_int_or_nan(x):
    s = str(x).replace(",", "").strip()
    return int(s) if s.isdigit() else None

df = pd.read_excel(
    "sales.xlsx",
    usecols=["顧客ID", "数量"],
    converters={
        "顧客ID": clean_id,
        "数量": to_int_or_nan
    }
)

summary = df.groupby("顧客ID", as_index=False)["数量"].sum()
print(summary.head())
Python

読み込み時に「IDのスペース除去」と「数量の数値化」を済ませているので、
後続の集計コードがとても素直になります。

テンプレ2:アンケートの「はい/いいえ」を True/False にしてから集計

import pandas as pd

def yes_no_to_bool(x):
    if x in ("はい", "YES", "Yes", "yes"):
        return True
    if x in ("いいえ", "NO", "No", "no"):
        return False
    return None

df = pd.read_excel(
    "survey.xlsx",
    converters={
        "同意": yes_no_to_bool
    }
)

print(df["同意"].value_counts(dropna=False))
Python

ここでは、読み込み時に「文字列 → ブール値」への変換を済ませているので、
value_counts でそのまま集計できます。


つまずきやすいポイントと注意点

converters の関数には「生の値」がそのまま来る

converters に渡される x は、Excelから読んだ“そのままの値”です。
空欄なら nan(float)、数値なら floatint、文字列なら str が来ます。

そのため、x.strip() とだけ書くと、x が文字列でないときにエラーになります。
安全に書くなら、まず文字列に変換してから処理するのがおすすめです。

lambda x: str(x).strip()
Python

こうしておけば、nan や数値が混ざっていても、とりあえず文字列として扱えます。

変換関数の中で例外が出ると、そのセルで止まる

converters の関数内でエラーが出ると、そのセルの読み込みで例外が発生します。
実務では、できるだけ try/except や条件分岐で「変換できないものは None にする」など、
壊れにくい関数を書くのが大事です。


小さな練習問題

練習1:customers.xlsx の「CustomerID」列の前後スペースを削って読み込む

条件は次の通りです。

  1. converters={"CustomerID": lambda x: str(x).strip()} を使う
  2. 読み込み後に df["CustomerID"].head() を表示して、スペースが消えているか確認する

練習2:survey.xlsx の「同意」列を True/False に変換して読み込み、集計する

条件は次の通りです。

  1. 「はい/YES/Yes/yes」を True、「いいえ/NO/No/no」を False、それ以外は None にする関数を書く
  2. それを converters に渡して読み込む
  3. value_counts(dropna=False) で分布を確認する

最後に

converters={'col': lambda x: x.strip()} は、
「この列は、こういうルールで“きれいにしてから”受け取りたい」という意思表示です。

これをうまく使うと、

読み込み後の前処理コードが減る
Excel側の“ゆるい書き方”を、Python側で一気に正規化できる
集計・結合・分析の前提が安定する

という、かなり大きなメリットが手に入ります。

あなたのExcelに、「毎回読み込んだあとに同じクリーニングを書いている列」があるなら、
その処理を converters に移してみてください。
入口を整えると、その先のコードが一気に軽くなります。

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