PythonでExcel書き出しの列の幅と数値の書式を整える手順|to_excelの後にopenpyxlで仕上げる
Pythonのpandasで書き出したExcelの、列の幅・桁区切り・パーセントの表示・見出しの固定を整える手順を解説します。列にまとめた書式が効かない理由やfloat_formatとの違いも、架空のデータで試した結果とともに紹介します。
目次
この記事でわかること
- pandasで書き出したExcelの、列の幅を決める方法
- 売上に桁区切り、前年比にパーセントの表示を付ける方法
- スクロールしても見出しの行が残るように固定する方法
- 列にまとめて付けた書式が、数字の見た目に効かない理由
Pythonで集計した表をExcelに書き出すと、列の幅が狭くて数字が「###」と表示されたり、売上に桁区切りが付いていなかったりします。毎回Excelで開いて手で直すのは手間です。ここでは、書き出しのときに列の幅と数字の見た目まで整えるやり方を、作り物の集計の表で実際に試した結果を添えて紹介します。
根拠は、pandas 3.1.0の公式のAPIリファレンス(to_excelとExcelWriter)と、openpyxlの公式の資料(スタイルの使い方と列の幅)です(2026年10月30日に原文で確認)。例に使う店舗・売上・前年比は、どれもこの記事のために作った値です。
先に結論: 書き出した後に、セルに1つずつ書式を付ける
先に結論を書くと、pandasで表を書き出した直後に、openpyxlのシートを受け取り、列の幅を決めて、数字のセルに1つずつ書式を付けます。 見出しの固定は、to_excelのfreeze_panesで指定できます。
| 整えたいこと | 使うもの |
|---|---|
| 列の幅 | column_dimensions |
| 桁区切り・% | number_format |
| 見出しの固定 | freeze_panes |
pandasでシートを受け取る
pandasのExcelWriterを使うと、to_excelで書き出した後のシートを受け取れます。pandasの資料では、ExcelWriterはブロックを抜けると自動で閉じる書き方(コンテキストマネージャー)で使うものとしていて、閉じたときにファイルが保存されます。sheetsという属性で、シートの名前からシートを取り出せます。
xlsxを書き出すときの道具(engine)は、何も指定しないとXlsxWriterが入っていればそれが使われ、入っていなければopenpyxlが使われます。この記事のコードはopenpyxlのやり方で書いているので、engine="openpyxl"を指定しています。
数字の見た目を整える(number_format)
openpyxlでは、セルのnumber_formatに書式の文字を入れると、数字の見た目が変わります。資料では、"0.00"で小数2桁で表示する例が示されています。売上には"#,##0"(桁区切り)、前年比には"0.0%"(パーセント)のように指定します。Excelの資料によると、パーセントの表示形式はセルの値を100倍して%を付けて表示するので、前年比は1.05のような比のままにしておきます。
注意したいのは、列や行にまとめて付けた書式です。openpyxlの資料では、列や行に付けた書式は、ファイルを閉じた後にExcelで作られるセルにだけ効き、表全体に付けたいときはセルに1つずつ付けるとしています。書き出した数字のセルには、1つずつ付けます。
見出しの行を固定する(freeze_panes)
to_excelのfreeze_panesに、固定する一番下の行と一番右の列を、1から数えた番号の組で渡します。(1, 0)とすると、1行目の見出しだけが固定されます。
手順: 集計の表を、書式を整えて別のファイルに書き出す
次のコードは、架空の集計の表 summary.xlsx(店舗・売上・前年比の3列)を読み込み、summary_formatted.xlsxとして書き出します。書き出した後に、列の幅を決め、売上に桁区切り、前年比にパーセントの書式を付けます。summary.xlsxは書き換えません。自分の表に合わせるときは、シートの名前・列の位置・幅の3つを変えてください。
import pandas as pd
# 集計の表を読み込む(summary.xlsx そのものは変えない)
summary = pd.read_excel("summary.xlsx")
with pd.ExcelWriter("summary_formatted.xlsx", engine="openpyxl") as writer:
# 1行目の見出しを固定して書き出す
summary.to_excel(writer, sheet_name="集計", index=False, freeze_panes=(1, 0))
ws = writer.sheets["集計"]
# 列の幅を決める
ws.column_dimensions["A"].width = 12
ws.column_dimensions["B"].width = 14
ws.column_dimensions["C"].width = 10
# 2行目から下の売上と前年比のセルに、1つずつ書式を付ける
for sales_cell, ratio_cell in ws.iter_rows(min_row=2, min_col=2, max_col=3):
sales_cell.number_format = "#,##0" # 売上: 桁区切り
ratio_cell.number_format = "0.0%" # 前年比: パーセント
pandasとopenpyxl(xlsxを読み書きする道具)は、あらかじめ入れておきます。前年比は、1.05のように比のままの値で入っている前提です。
実行した結果
架空の集計の表(3行。売上は7桁までの整数、前年比は1.052のような比)で動かしました。
- 書き出したsummary_formatted.xlsxを読み直すと、2行目から下の売上には桁区切り(#,##0)、前年比にはパーセント(0.0%)の書式が付き、見出しの行は書式なし(General)のままでした
- 見出しの行は固定され、列の幅はA・B・Cの順に12・14・10になりました
- セルの値そのものは変わらず、売上は整数、前年比は1.052のままでした
- 読み込んだsummary.xlsxのほうは、実行の前後でバイト単位で同じでした
動作を確かめたのは、Macの作業PC(Python 3.12.15、pandas 3.1.0、openpyxl 3.1.5)です。
自分で直すか、相談するかの判断
判断の目安は、「その表を、計算に使うか、見るだけか」です。見るだけの報告の表なら、この記事のように見た目を整えれば十分です。
ほかの人がその表で計算を続けるなら、数字を丸めて書き出すと、合計が合わなくなることがあります。見た目だけを変える書式にとどめ、どこまで丸めてよいかは、表を使う人に確かめてから決めます。
つまずきやすいところ
- 列にまとめて書式を付ける: 架空の表で、列に桁区切りの書式を付けただけでは、書き出した売上のセルは「General」のままでした。セルに1つずつ付けます
- float_formatで丸めてしまう: 前年比をfloat_format="%.1f"で書き出すと、1.052が1.1として保存され、値そのものが変わりました。見た目だけを変えるならnumber_formatを使います
- 百倍した値にパーセントを付ける: 前年比が105のように入っていると、Excelはパーセントの書式で値を100倍して表示するため、10500.0%になります。架空の表でも、値は105のまま書式だけが付きました
- openpyxlのやり方なのに、道具を指定しない: XlsxWriterが入っている環境では、書き出しにXlsxWriterが使われ、この記事のcolumn_dimensionsなどの書き方が合わなくなります。engine="openpyxl"を指定します
- 集計してから書き出したいとき: 行と列の2つの項目で合計した表の作り方は、PythonでExcelのピボットテーブルのように集計する手順で紹介しています
- 毎週の集計表まで自動で作りたいとき: 決まった形の集計表を毎週作る流れは、Excelの定型レポートを自動化する手順にまとめています
- 店舗ごとにシートを分けて書き出したいとき: 分け方は、PythonでExcelの表を条件で分けて別々のシートに保存する手順で紹介しています
まとめ
- 書き出した直後にExcelWriterのsheetsからシートを受け取り、列の幅と書式を整えます
- 数字の見た目はnumber_formatで変え、セルに1つずつ付けます。列にまとめて付けても、書き出したセルには効きません
- 見出しの行は、to_excelのfreeze_panes=(1, 0)で固定できます
- float_formatは値そのものを丸めるため、計算に使う表では見た目だけを変える書式を使います
よくある質問
列ごとに書式を付けたのに、数字の見た目が変わらないのはなぜですか?
openpyxlの資料では、列や行に付けた書式は、ファイルを閉じた後にExcelで作られるセルにだけ効くとしています。架空の表でも、列に桁区切りの書式を付けただけでは、書き出した数字のセルは「General」のままでした。セルに1つずつ付けます。
float_formatとnumber_formatは、何が違いますか?
float_formatは、書き出す前に数字そのものを丸めます。架空の表で前年比をfloat_format="%.1f"で書き出すと、1.052は1.1として保存されました。number_formatは見た目だけを変え、セルの値はそのまま残ります。計算に使う表では、見た目だけを変える方を選びます。
パーセントの書式を付けたら、105.0%ではなく10500.0%になるのはなぜですか?
セルの値が105のように、すでに百倍された数で入っているためです。Excelの資料では、パーセントの表示形式は、セルの値を100倍して%を付けて表示するとしています。架空の表でも、値は105のまま、書式だけが0.0%になりました。割合は1.05のように、もとの比のまま入れておきます。
列の幅には、どんな値を入れればよいですか?
openpyxlの資料では、列の幅は小数の値で指定するとしています。どのくらいの見え方になるかはフォントや環境で変わるため、一度書き出してExcelで開き、見出しと数字が収まる値に調整します。
書き出した後に、元の集計のファイルは変わりますか?
変わりません。記事のコードは元のファイルを読むだけで、書式を付けた表は別の名前のファイルに書き出します。試したときも、読み込んだsummary.xlsxは実行の前後で同じでした。