Python Excel操作 逆引き集 | DataFrameの列幅を自動調整して書き出す(xlsxwriter + 計算)

Python
スポンサーリンク

何をやりたいテクニックなのか

ゴールはこうです。

「pandas の DataFrame を Excel に書き出すとき、
列幅を“中身にちょうどいい幅”に自動調整したい」

xlsxwriter をエンジンに使い、
worksheet.set_column() に「計算した幅」を渡すことで実現します。

ポイントは、

  1. まず普通に to_excel で書き出す
  2. DataFrame の中身(ヘッダー+データ)から「最大文字数」を列ごとに計算する
  3. その文字数をもとに set_column で列幅を設定する

という三段構えです。


基本パターンの全体像

最小の「自動列幅調整つき to_excel」

import pandas as pd

df = pd.DataFrame({
    "日付": ["2025-01-01", "2025-01-02"],
    "商品": ["りんご", "みかん"],
    "金額": [1000, 123456]
})

with pd.ExcelWriter("auto_width.xlsx", engine="xlsxwriter") as writer:
    df.to_excel(writer, sheet_name="売上", index=False)

    workbook  = writer.book
    worksheet = writer.sheets["売上"]

    for i, col in enumerate(df.columns):
        col_data = df[col].astype(str).tolist()
        col_data.append(str(col))
        max_len = max(len(s) for s in col_data)
        width = max_len + 2
        worksheet.set_column(i, i, width)
Python

これで、「ヘッダー+その列の中で一番長い値」に合わせて、
各列の幅が自動的に調整された Excel ができます。

ここから、重要な部分を一つずつ分解していきます。


列幅を決めるための「長さの計算」を理解する

なぜ DataFrame 側で長さを計算するのか

xlsxwriter 自体には「自動で列幅をいい感じにしてくれる」機能はありません。
だから、自分で「この列は何文字くらい必要か」を計算してあげる必要があります。

やっていることはシンプルで、

  1. その列の全データを文字列に変換する
  2. 列名(ヘッダー)も候補に入れる
  3. その中で一番長い文字列の長さを取る
  4. その長さに少し余裕を足して列幅にする

という流れです。

コードの中身をかみ砕いて読む

for i, col in enumerate(df.columns):
    col_data = df[col].astype(str).tolist()
    col_data.append(str(col))
    max_len = max(len(s) for s in col_data)
    width = max_len + 2
    worksheet.set_column(i, i, width)
Python

enumerate(df.columns)
→ 列名と、その列の番号(0,1,2,…)を同時に取る

df[col].astype(str).tolist()
→ その列の値を全部文字列にして、リストにする

col_data.append(str(col))
→ 列名(ヘッダー)も候補に入れる(ヘッダーの方が長いこともある)

max_len = max(len(s) for s in col_data)
→ その列の中で一番長い文字列の長さを求める

width = max_len + 2
→ ぴったりだと窮屈なので、2 文字ぶんくらい余裕を足す

worksheet.set_column(i, i, width)
→ i 列目(A=0, B=1, …)の幅を width に設定する

この「長さを計算して set_column に渡す」というパターンさえ理解すれば、
あとは応用でどうとでもできます。


実務テンプレート:集計結果を自動列幅つきで出す

月次集計をきれいな列幅で出力する例

import pandas as pd

df = pd.read_excel("sales.xlsx", parse_dates=["日付"])
df["金額"] = pd.to_numeric(df["金額"], errors="coerce")

monthly = (
    df.assign(=df["日付"].dt.to_period("M"))
      .groupby("月", as_index=False)["金額"].sum()
)

with pd.ExcelWriter("sales_monthly_auto_width.xlsx", engine="xlsxwriter") as writer:
    monthly.to_excel(writer, sheet_name="月次集計", index=False)

    workbook  = writer.book
    worksheet = writer.sheets["月次集計"]

    for i, col in enumerate(monthly.columns):
        col_data = monthly[col].astype(str).tolist()
        col_data.append(str(col))
        max_len = max(len(s) for s in col_data)
        width = max_len + 2
        worksheet.set_column(i, i, width)
Python

このテンプレートをベースにすれば、

どんな DataFrame でも
どんなシート名でも

「中身に合わせた列幅」で出力できるようになります。


もう少しだけ丁寧にしたバージョン(日本語・数値を意識する)

全角文字やカンマ付き数値を考慮したい場合の工夫

Excel の列幅は「文字数」と完全に 1:1 ではありません。
全角文字は広く見えたり、フォントによっても変わります。

厳密にやり始めるとキリがないので、
現場では「だいたいこれで困らない」くらいの調整で十分です。

例えば、全角文字が多い列には少し余裕を多めに取る、
数値列は固定幅にする、などの工夫もできます。

for i, col in enumerate(df.columns):
    col_data = df[col].astype(str).tolist()
    col_data.append(str(col))
    max_len = max(len(s) for s in col_data)

    if df[col].dtype.kind in "if":  # 数値列なら
        width = max(10, max_len + 2)
    else:
        width = max_len + 2

    worksheet.set_column(i, i, width)
Python

ここでは、

数値列は最低 10 くらいの幅を確保
文字列列は「最大文字数+2」

というざっくりルールを入れています。


よくあるつまずきポイント

なぜ engine=”xlsxwriter” が必要なのか

worksheet.set_column は XlsxWriter のメソッドです。
engine="xlsxwriter" を指定していないと、writer.bookwriter.sheets[...]
XlsxWriter のオブジェクトにならず、このメソッドが使えません。

「列幅をいじる」「書式をいじる」など、
Excel の見た目を触りたいときは、必ず engine="xlsxwriter" をセットで書く、
と覚えておいてください。

既存ファイルに追記するときは向いていない

mode="a" で既存ファイルにシート追加したい場合は、
engine="openpyxl" を使うのが基本です。

XlsxWriter は「新規作成専用」と割り切ると、
頭の中が整理しやすくなります。


小さな練習アイデア

自分で、文字数のバラバラな列を持つ DataFrame を作って、

  1. 普通に to_excel したもの
  2. 上の「自動列幅調整コード」を使ったもの

の 2 つを出力して、Excel で見比べてみてください。

「列幅をちゃんと調整するだけで、こんなに読みやすさが変わるのか」という感覚が、
一度体験として入ると、このテクニックは手放せなくなります。

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