Python Excel操作 逆引き集 | 読み込み時にデータ型を指定する

Python Python
スポンサーリンク

「型を決めてから読む」という発想を持つ

Excelは何でも受け入れてくれるので、同じ列に数字・文字・空白が混ざっていることがよくあります。
そのまま read_excel に任せると、pandasが「たぶんこうだろう」と推測して型を決めますが、それがこちらの意図とズレることが多いです。

そこで使うのが dtype です。
dtype={"col": str} のように指定すると、「この列はこういう型で読んでくれ」と、こちらからはっきり指示できます。
読み込み時に型を決めておくと、その後の処理が安定し、バグも減ります。


基本形:dtype={‘col’: str} の意味を理解する

最小コードと挙動

import pandas as pd

df = pd.read_excel(
    "customers.xlsx",
    dtype={"CustomerID": str}
)

print(df.dtypes)
print(df.head())
Python

ここで dtype={"CustomerID": str} と書くことで、「CustomerID 列は文字列として読み込む」と指定しています。
Excel側で数値っぽく見えていても、先頭ゼロがあっても、必ず文字列として扱われます。

重要なのは、「pandasに推測させない」という姿勢です。
ID・コード・郵便番号など、「数値っぽいけど計算しないもの」は、基本的に文字列で読む、と決めてしまうと安定します。

複数列をまとめて指定する

df = pd.read_excel(
    "orders.xlsx",
    dtype={
        "OrderID": str,
        "CustomerID": str,
        "ZipCode": str
    }
)

print(df.dtypes)
Python

このように、辞書で複数列を一度に指定できます。
「このファイルでは、これらの列は全部文字列で扱う」というルールを、読み込み時に宣言しているイメージです。


よく使う型指定パターン

コード・ID・郵便番号を文字列で読む

import pandas as pd

df = pd.read_excel(
    "master.xlsx",
    dtype={
        "商品コード": str,
        "顧客ID": str,
        "郵便番号": str
    }
)

print(df.dtypes)
Python

ここが一番重要です。
これらを数値として読むと、先頭ゼロが消えたり、桁数が変わったりして、後で結合や検索がうまくいかなくなります。

「計算しない数値っぽい列は、全部文字列にする」
このルールを持っておくだけで、かなりのトラブルを避けられます。

整数列に欠損がある場合(nullable 整数型)

pandasの通常の int64 型は「欠損(NaN)を持てない」という制約があります。
数量や個数の列に欠損があり得る場合は、Int64(大文字I)という「欠損を許容する整数型」を使います。

import pandas as pd

df = pd.read_excel(
    "sales.xlsx",
    dtype={
        "数量": "Int64"   # 欠損ありの整数
    }
)

print(df.dtypes)
print(df["数量"].isna().sum())
Python

"Int64" を使うと、欠損は NaN のまま、値は整数として扱えます。
「全部埋まっているはず」と思っていても、現場データには平気で空欄が混ざるので、数量系は最初から "Int64" を想定しておくと安全です。

浮動小数点(小数を含む数値)

単価や金額(小数あり)などは、float で指定できます。

import pandas as pd

df = pd.read_excel(
    "prices.xlsx",
    dtype={
        "単価": float,
        "割引率": float
    }
)

print(df.dtypes)
Python

ただし、Excel側に文字や記号が混ざっていると、dtype=float で読み込み時にエラーになることがあります。
その場合は、いったん文字列で読み込んでから pd.to_numeric(..., errors="coerce") で変換する方が安全です。


dtype と parse_dates・converters の関係

日付は dtype ではなく parse_dates で扱う

日付列を dtype=str にしてしまうと、毎回自分で to_datetime する必要が出てきます。
日付は dtype ではなく parse_dates で指定するのが基本です。

import pandas as pd

df = pd.read_excel(
    "sales.xlsx",
    dtype={"CustomerID": str},
    parse_dates=["Date"]
)

print(df.dtypes)
Python

ここでは、「CustomerID は文字列」「Date は datetime64[ns]」という形で読み込まれます。
日付列があるなら、まず parse_dates を検討し、それ以外の列に dtype を使う、という順番で考えると整理しやすくなります。

複雑な変換は converters と併用する

カンマ付き金額や単位付き数値など、「そのままでは数値にならない」列に対しては、dtype だけでは足りません。
その場合は converters で加工しつつ、結果の型を揃えます。

import pandas as pd

def clean_amount(x):
    if pd.isna(x):
        return None
    s = str(x).replace(",", "").replace("円", "").strip()
    return float(s) if s else None

df = pd.read_excel(
    "sales.xlsx",
    dtype={"顧客ID": str},
    converters={"金額": clean_amount}
)

print(df.dtypes)
Python

ここでは、「顧客IDは文字列」「金額は converters で float に変換」という役割分担になっています。
dtype は「そのまま型を決められる列」に、converters は「加工が必要な列」に、という使い分けがポイントです。


実践テンプレートでイメージを固める

テンプレ1:顧客マスタを「文字列中心」で安定して読む

import pandas as pd

df = pd.read_excel(
    "customer_master.xlsx",
    dtype={
        "CustomerID": str,
        "ZipCode": str,
        "Phone": str
    }
)

print(df.dtypes)
print(df.head())
Python

このテンプレートは、「結合キーや連絡先情報を、絶対に壊したくない」場面で使います。
数値として計算しない列は、最初から文字列にしておくのが鉄則です。

テンプレ2:売上明細を「IDは文字列・数量は整数・金額は数値」で読む

import pandas as pd

df = pd.read_excel(
    "sales_detail.xlsx",
    dtype={
        "OrderID": str,
        "CustomerID": str,
        "Qty": "Int64"
    },
    parse_dates=["Date"]
)

df["Amount"] = pd.to_numeric(df["Amount"], errors="coerce")

print(df.dtypes)
print(df.head())
Python

ここでは、

  • ID系は文字列
  • 数量は欠損許容の整数
  • 日付は datetime
  • 金額は後から数値化

という、かなり現実的な型設計になっています。
このレベルまで読み込み時に決めておくと、後の集計や結合が非常にスムーズになります。


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

dtype を厳しく指定しすぎて読み込み時にエラーになる

例えば、dtype={"Qty": int} としているのに、Excel側に空欄や文字が混ざっていると、読み込み時にエラーになります。
数量系は最初から "Int64"(nullable 整数)にしておくか、いったん文字列で読み込んでから to_numeric(errors="coerce") で変換する方が安全です。

文字列にしたら数値計算がしづらくなった

IDやコードは文字列で良いですが、本当に計算したい列まで str にしてしまうと、毎回変換が必要になります。
「計算する列」と「計算しない列」を頭の中で分けておき、計算する列は float"Int64"、計算しない列は str、という整理をしておくと迷いにくくなります。

dtype と parse_dates を同時に同じ列に指定しない

同じ列に対して dtypeparse_dates を両方指定すると、意図しない挙動になることがあります。
日付は parse_dates に任せ、dtype では触らない、というルールにしておくとシンプルです。


小さな練習問題

練習1:customers.xlsx を「ID・郵便番号・電話番号は文字列」で読む

条件は次の通りです。

  1. CustomerID, ZipCode, Phone をすべて文字列で読む
  2. 読み込み後に df.dtypes を表示して、型が想定通りか確認する

自分でコードを書いてみて、「どの列を文字列にすべきか」を意識してみてください。

練習2:sales.xlsx を「IDは文字列・数量は欠損許容整数・日付は datetime」で読む

条件は次の通りです。

  1. OrderID, CustomerID を文字列で読む
  2. Qty"Int64" で読む
  3. Dateparse_dates で datetime にする
  4. 読み込み後に df.dtypesdf.head() を確認する

ここまでできると、「読み込み時に型を設計する」という感覚がかなり身についてきます。


最後に

dtype={'col': str} は、「この列はこう扱う」というあなたの意思表示です。
pandasに推測させるのではなく、自分で型を決めることで、

  • 先頭ゼロが消えない
  • 結合キーが壊れない
  • 集計や変換が安定する

という、とても大きなメリットが得られます。

「この列は本当に数値として計算したいのか? それとも、ただのラベルか?」
それを一つずつ考えながら dtype を書いていくと、Excel処理の精度と安心感が一段上がります。

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