PythonでExcelの表に順位の列を付ける手順|rankで同じ値や店舗ごとの順位を決める
Pythonのpandasのrankで、Excelの売上の表に「全体の順位」と「店舗の中の順位」の列を足す手順を解説します。同じ売上の人の順位の付け方や、小さい順になってしまう原因も、架空の売上の表で試して紹介します。
目次
この記事でわかること
- 行の並びを変えずに、順位の列を足す方法(rank)
- 大きい順にする指定と、同じ値の行の順位の付け方
- 店舗ごとに1位から順位を付ける方法
- 売上が空欄の行の扱いと、自分の表で使う前に確かめること
担当者の売上の表に順位を付けるとき、表を並べ替えてから1、2、3と手で打ち込んでいませんか。並べ替えると元の並びが崩れ、同じ売上の人がいると番号の付け方にも迷います。この記事では、元の並びのまま「全体の順位」と「店舗の順位」の列を足す手順を紹介します。
根拠にしたのは、pandas 3.1.0のSeries.rankとDataFrameGroupBy.rankの公式の説明で、2026年10月31日に原文を読みました。売上の表は、この記事のために作った架空のものです。
先に結論: ascending=Falseとmethod="min"を指定する
売上の列にrankを使い、ascending=Falseで大きい順に、method="min"で同じ売上を同じ順位にします。 店舗の中の順位は、groupbyで店舗に分けてからrankを使います。
同じ値の行の順位は、methodで変わります。試した表で、40万円の2人と、その次の30万円の3人に付いた順位は次のとおりです。
| method | 40万円の2人 | 30万円の3人 |
|---|---|---|
| "average"(初期設定) | 2.5位 | 5位 |
| "min" | 2位 | 4位 |
| "dense" | 2位 | 3位 |
| "first" | 2位・3位 | 4〜6位 |
rankのしくみ
pandasの資料では、rankは1からnまでの順位を計算するとしています。初期設定では、同じ値の行には、それらの順位の平均が付きます。
同じ値の行の扱いはmethodで選べます。"min"はそのグループで最も小さい順位、"dense"は"min"と同じ考え方で、次の値の順位を1つずつしか増やしません。"first"は、表に出てくる順に順位を付けます。
ascendingの初期設定は小さい順です。groupbyのrankの資料では、Falseにすると大きい値から1位になると説明しています。
手順: 全体と店舗ごとの順位の列を作る
次のコードは、架空の表 staff_sales.xlsx の「店舗」と「売上」から「全体の順位」と「店舗の順位」の列を作り、staff_sales_ranked.xlsx という別の名前で保存します。元の staff_sales.xlsx はそのまま残ります。
import pandas as pd
# 担当者別の売上の表を読む(順位を付けた表は別の名前で保存する)
table = pd.read_excel("staff_sales.xlsx")
# 売上の大きい順に1位から。同じ売上は同じ順位にする
overall = table["売上"].rank(ascending=False, method="min")
table["全体の順位"] = overall.astype("Int64")
# 店舗の中での順位
in_store = table.groupby("店舗")["売上"].rank(ascending=False, method="min")
table["店舗の順位"] = in_store.astype("Int64")
print(table)
print("順位が空の行:", table["全体の順位"].isna().sum())
table.to_excel("staff_sales_ranked.xlsx", index=False)
astype("Int64")は、順位を整数の列にするためです。空の行は空のまま残ります。xlsxの読み書きにはopenpyxlも要ります。
試した結果
担当者が8人だけの作り物の表で動かしました。本店は50万・30万・30万円・空欄、駅前店は40万・30万・20万・40万円です。
- 全体の順位は、50万円が1位、40万円の2人が2位、30万円の3人が4位、20万円が7位になりました
- 店舗の順位は、本店が1位・2位・2位、駅前店が1位・3位・4位・1位でした
- 売上が空欄の本店の行は、全体の順位も店舗の順位も空になり、「順位が空の行: 1」と表示されました
- 順位の列は、小数ではなく整数の列で書き出されました
- 元の staff_sales.xlsx は、実行の前後でハッシュ値が変わりませんでした
作業PCはMacで、ライブラリの版はpandas 3.1.0とopenpyxl 3.1.5、Python本体は3.12.15です。書き出したファイルはExcelで開いておらず、表示の確認はしていません。
自分で直すか、相談するかの判断
目安は、「同じ値の人の順位を、どう決めるかを1文で言えるか」です。「同じ売上なら同じ順位で、次の人は人数の分だけ下がる」と言えるなら"min"、「次の人は1つ下」なら"dense"のように、言葉がそのまま指定になります。
同じ売上のときに件数や日付で上下を決める、といった決まりがある場合は、rankだけでは足りません。先に決まりの順に表を並べてから"first"を使うかどうかを、順位を使う人と相談して決めます。
つまずきやすいところ
- 小さい順になる: 試したときも、ascendingを付けないと、50万円の人が7位、20万円の人が1位になりました。売上の順位なら、ascending=Falseを付けます
- 同じ売上の順位が2.5位になる: methodを付けないと、40万円の2人は2.5位、30万円の3人は5位になりました。整数の順位にしたいなら、methodを指定します
- 店舗に分けずに順位を付ける: 全体の順位を店舗の順位のつもりで使うと、駅前店の1位が全体の2位のままになります。店舗の中の順位はgroupbyで分けてから付けます
- 上位の行だけを取り出したい: 順位の列ではなく、上位10件を別のファイルにしたいときは、PythonでExcelの表を並べ替えて上位の行を取り出す手順のほうが向いています
- 順位と一緒に、店舗の中の割合も出したい: 店舗の合計に対する割合の列を足す方法は、PythonでExcelのグループごとの割合の列を作る手順で紹介しています
- 順位の列を中央にそろえて見せたい: 書き出したファイルの列の幅や書式の整え方は、PythonでExcel書き出しの列の幅と数値の書式を整える手順にまとめています
まとめ
- rankは、行の並びを変えずに順位を返します
- 大きい順ならascending=False、同じ値の扱いはmethodで決めます
- 店舗ごとの順位は、groupbyで分けてからrankを使います
- 空の行は順位も空になるので、件数を数えて確かめます
よくある質問
並べ替え(sort_values)と、rankは何が違いますか?
sort_valuesは行の並びを変えます。rankは行の並びを変えずに、各行の順位を数字で返します。元の表の並びのまま順位の列を足したいときはrankを使います。
順位が「1.0」「2.5」のように小数で出るのはなぜですか?
rankの結果は小数の型で返り、初期設定では同じ値の行に順位の平均が付くためです。methodに"min"を渡すと同じ値は同じ整数の順位になり、astype("Int64")で整数の列にできます。
同じ売上の人にも、違う順位を付けたいときは?
methodに"first"を渡します。公式の資料では、表に出てくる順に順位を付けるとしています。先に出てきた行が上の順位になるので、決め方を表の並びに任せてよいかを確かめてから使います。
上位何%に入るかを出せますか?
rankにpct=Trueを渡すと、順位を割合で返します。公式の資料では、順位を百分位の形で表すかどうかを決める引数としています。
売上が空の人を最下位にしたいときは?
na_optionに"bottom"を渡します。試した表でも、大きい順の順位で空の行が8位になりました。空の行を順位に入れるかどうかは、表を使う人と決めてから選びます。