PythonでExcelの数値を四捨五入する手順|roundが偶数に丸める理由とDecimalでの直し方
PythonやpandasのroundでExcelの数値を丸めると、0.5が切り上がらずExcelのROUNDと結果がずれることがあります。偶数に丸める理由と、decimalのROUND_HALF_UPで四捨五入にそろえる手順を、架空のデータで試して解説。
目次
この記事でわかること
- Pythonのroundとpandasのroundが、0.5を偶数の側に丸める理由
- ExcelのROUNDと同じ四捨五入にそろえる方法(decimalのROUND_HALF_UP)
- 小数の誤差・マイナスの値・空欄のつまずき
- 自分で直すか、相談するかの判断の目安
割り勘の金額をPythonのroundで1円単位にそろえると、Excelの四捨五入と結果が合わない行が出ることがあります。試した表でも、1252.5円が1253円にならず、1252円になりました。これはまちがいではなく、Pythonのroundの決まりです。この記事では、その決まりと、四捨五入にそろえるコードをまとめます。
元にした資料は、Pythonの公式の資料(組み込み関数のround、decimal)、NumPyのnumpy.round、pandas 3.1.0のSeries.round、MicrosoftのROUND関数の説明で、2026年11月1日に原文を読みました。表の金額と人数は、例として作った架空のものです。
先に結論: 四捨五入にしたい列は、Decimalにしてから丸める
round(Pythonの組み込みとpandasの両方)は、ちょうど真ん中の値を偶数の側に丸めます。 0.5をいつも切り上げたいときは、値を文字にしてからDecimalにし、quantizeにROUND_HALF_UPを渡して丸めます。
| 値 | roundの結果 | ROUND_HALF_UPの結果 |
|---|---|---|
| 1252.5 | 1252 | 1253 |
| 1503.5 | 1504 | 1504 |
| 500.5 | 500 | 501 |
| -1252.5 | -1252 | -1253 |
roundが偶数に丸めるしくみ
Pythonの資料では、組み込みのroundは、2つの候補が同じだけ近いときは偶数の側に丸めると書いています。例として、round(0.5)とround(-0.5)はどちらも0、round(1.5)は2になります。
pandasのroundも同じです。Series.roundの資料には、ちょうど真ん中の値はいちばん近い偶数に丸めると書かれています。NumPyの資料でも、1.5と2.5はどちらも2.0になる、という例を挙げています。
一方で、Microsoftの資料に載っているExcelのROUNDの例では、2.15を小数第1位に丸めると2.2、-1.475を小数第2位に丸めると-1.48です。例を見ると、0.5のところで大きいほう(マイナスなら0から遠いほう)へ丸めているため、Pythonのroundとは結果が分かれることがあります。
decimalのROUND_HALF_UPで四捨五入にする
decimalは、10進数のまま計算するためのPythonの標準の道具です。資料では、ROUND_HALF_UPを、いちばん近いほうへ丸め、ちょうど真ん中なら0から遠い側へ丸めるやり方だと説明しています。
丸めにはquantizeを使います。資料では、決まった桁数に丸めることの多いお金の計算に向く方法だとしています。渡す単位を"1"にすれば整数に、"0.01"にすれば小数第2位までに丸まります。
手順: 割り勘の金額を1円単位に四捨五入して書き出す
次のコードは、架空の表 split_bill.xlsx(項目・金額・人数の3列)を読み、1人あたりの金額を出して、roundの結果と四捨五入の結果を並べて split_bill_rounded.xlsx に書き出します。split_bill.xlsx には書き込みません。
from decimal import Decimal, ROUND_HALF_UP
import pandas as pd
# 割り勘の表を読む(元のファイルには書き込まない)
bill = pd.read_excel("split_bill.xlsx")
bill["1人あたり"] = bill["金額"] / bill["人数"]
def round_half_up(value, unit="1"):
# str()で文字にしてからDecimalにすると、小数の誤差を持ち込まない
rounded = Decimal(str(value)).quantize(Decimal(unit), rounding=ROUND_HALF_UP)
return float(rounded)
# 比べるために、roundの結果と四捨五入の結果を並べる
bill["roundの結果"] = bill["1人あたり"].round(0)
bill["四捨五入"] = bill["1人あたり"].apply(round_half_up)
print(bill)
bill.to_excel("split_bill_rounded.xlsx", index=False)
使うには、pandasとopenpyxlを入れておきます。decimalはPythonに最初から入っています。
試した結果
金額と人数を組み合わせた6行の架空の表で動かしました。1人あたりがちょうど0.5になる行を3つ、割り切れる行と割り切れない行を1つずつ、返金のマイナスの行を1つ入れています。
- 1252.5円・1503.5円・500.5円は、roundでは1252・1504・500、四捨五入では1253・1504・501になりました。1503.5は、どちらでも1504です
- 333円ちょうどの行と、333.33…円の行は、どちらの方法でも333でした
- 返金の-1252.5円は、roundでは-1252、四捨五入では-1253になりました
- split_bill_rounded.xlsx は、6行・6列でした
- 元の split_bill.xlsx のハッシュ値は、実行の前後で同じでした
動かしたのは作業用のMacで、表の読み書きにはpandas 3.1.0とopenpyxl 3.1.5を、Python本体は3.12.15を使いました。書き出した表をExcelのアプリで開いて、ROUNDと見比べることはしていません。
自分で直すか、相談するかの判断
目安は、「どの規則で丸めるかが決まっているか」です。社内の決まりや請求書の作りで「四捨五入」と決まっていれば、上のround_half_upに置きかえるだけで済みます。
税の計算や、合計してから丸めるのか1行ずつ丸めるのか、といった決まりがはっきりしないときは、経理の担当の人や取引先と、丸め方と丸める場所を先に決めます。決まった後は、Excelで出した数字と何行か照らし合わせてから使います。
つまずきやすいところ
- 数をそのままDecimalに渡す: 資料では、小数からDecimalを作るとその値を正確に写すとしています。試したときも、2.675をそのまま渡して小数第2位に四捨五入すると2.67になり、str()を通すと2.68になりました
- 0.5を足して切り捨てる: 試したときも、-1252.5に0.5を足して切り捨てると-1252になり、マイナスの値ではExcelのROUNDと分かれました。ROUND_HALF_UPを使う方が確かです
- 空欄の行がある: 1人あたりが空欄(NaN)の行は、round_half_upに通しても空欄のままで、エラーにはなりませんでした。空欄を0として扱うかは、先に決めておきます
- 割合を丸めると合計が100にならない: 割合の列を丸めるときの注意は、PythonでExcelのグループごとの割合の列を作る手順にまとめています
- 見た目だけ整えたい: 値は丸めずに、書き出した後で数値の書式を付ける方法は、PythonでExcel書き出しの列の幅と数値の書式を整える手順で紹介しています
- 集計してから丸めたい: 項目ごとの合計を先に出す方法は、PythonでExcelのピボットテーブルのように集計する手順の方法が使えます
まとめ
- Pythonとpandasのroundは、ちょうど真ん中の値を偶数の側に丸めます
- 四捨五入にしたいときは、str()で文字にしてからDecimalにし、quantizeにROUND_HALF_UPを渡します
- ROUND_HALF_UPは、マイナスの値を0から遠い側に丸めます
- どこで、どの規則で丸めるかを先に決めてから、コードに置きかえます
よくある質問
roundの偶数への丸めは、バグですか?
バグではありません。Pythonの資料では、2つの候補が同じだけ近いときは偶数の側に丸めると書いており、round(0.5)とround(-0.5)はどちらも0、round(1.5)は2になる例を挙げています。NumPyとpandasの資料にも、ちょうど真ん中の値はいちばん近い偶数に丸めると書かれています。
小数第2位までの四捨五入にしたいときは?
quantizeに渡す単位を"0.01"にします。試した環境でも、2.675を"0.01"の単位で四捨五入すると2.68になりました。同じ値をroundで小数第2位に丸めると2.67です。
Decimal(2.675)のように、数をそのまま渡してはいけないのですか?
おすすめしません。資料では、小数(float)からDecimalを作ると、その値を正確に写すとしています。2.675は小数の形では2.67499…と少し小さく持たれているため、試したときも、数をそのまま渡すと2.67になりました。str()で文字にしてから渡すと、見た目どおりの2.675として扱えます。
マイナスの値は、どちらに丸まりますか?
ROUND_HALF_UPは、ちょうど真ん中のときに0から遠い側へ丸めます。試した表でも、-1252.5は-1253になりました。Microsoftの資料の例でも、ExcelのROUNDで-1.475を小数第2位に丸めると-1.48です。
Excelで丸めるのと、Pythonで丸めるのと、どちらがよいですか?
丸めた値をこの後の計算に使うなら、Pythonの側で一度だけ丸め、その値をExcelに書き出すと、どこで丸めたかが分かりやすくなります。見た目だけ整えたいときは、値は丸めずに、書き出しの後で数値の書式を付ける方法もあります。