この記事でわかること

  • 小・中・大のような、自分で決めた順番で行を並べ替える方法
  • 列の値はそのままにして、並べ替えの基準だけに順番を付ける書き方
  • 決めた順番に無い値や空欄の行が、どこに並ぶか
  • 同じ値の行の並びを、読み込んだ順のままにする指定

注文の一覧をサイズの小・中・大の順に、支店の一覧を北から南の地域の順に並べたい場面があります。毎月同じ並べ方をくり返すなら、順番の一覧をコードに書いておくと、手順がぶれません。この記事では、pandasで注文の一覧を読み込み、決めた順番に並べた表を別のファイルに書き出すまでを、手元で試した結果と一緒に説明します。

参照したのは、pandas 3.1.1の公式の資料(順番つきの区分のユーザーガイド、pandas.Categorical、DataFrame.sort_values)と、3.0.0のリリースノートで、2026年11月5日に原文で確かめました。注文番号やサイズは、どれも試すために作った架空の値です。

先に結論: 並べ替えの基準だけを、順番つきの区分にする

sort_valuesのkeyに、決めた順番の一覧から作った順番つきの区分(Categorical)を返す関数を渡すと、その順番で並びます。 列の値そのものは変えないので、順番に無い値も書き出すファイルに残ります。

したいこと 書き方 架空の注文の一覧での結果
決めた順番に並べる sort_values("サイズ", key=関数, kind="stable") 小5行・中6行・大6行の順
順番に無い値を確かめる ~列.isin(順番の一覧) LL・「大 」・空欄の3行
逆の順番に並べる ascending=False を足す 大・中・小の順
順番に無い行を先頭に出す na_position="first" を足す 3行が先頭に

順番つきの区分(Categorical)のしくみ

pandasの順番つきの区分は、値と、取りうる値の一覧(categories)を組にして持ちます。資料では、順番は値の文字の並びではなく、categoriesの並びで決まると説明しています。orderedをTrueにすると、並べ替えのときにcategoriesの順を守ります。

categoriesを渡したときに一覧に無い値は、資料の説明ではNaNに置きかえられます。ただし、pandas 3.0.0のリリースノートで、一覧に無い値を含むまま区分を作ることは非推奨になりました。試した3.1.1でも、そのまま作ると「将来はエラーにする」という警告が出ました。この記事のコードでは、一覧にある値だけを残してから区分にしています。

並べ替えのsort_valuesには、並べる前の値に関数をかけるkeyと、同じ値の並びを保つ並べ方を選ぶkindがあります。資料では、kindのstableとmergesortだけが、同じ値どうしの元の順番を保つとしています。空の値の位置はna_positionで決まり、初めの設定は最後です。

手順: 注文の一覧をサイズの小・中・大の順に並べて書き出す

次のコードは、架空の注文の一覧 chumon.xlsx を読み込み、サイズの列を小・中・大の順に並べた表を chumon_narabi.xlsx に書き出します。元の chumon.xlsx は書きかえません。名前の付いた3か所(ファイル・列・順番の一覧)は、手元の表に合わせて書きかえます。なお、コードの最初の3行で順番と読み込みを決めています。

import pandas as pd

junban = ["小", "中", "大"]  # 並べたい順番
chumon = pd.read_excel("chumon.xlsx")  # 読むだけで、上書きはしない

# 決めた順番に無い値の行を、先に画面で確かめる
nai = chumon.loc[~chumon["サイズ"].isin(junban), ["注文番号", "サイズ"]]
print("順番に無い値の行:", nai.values.tolist())


def jun(s):
    # 順番にある値だけを順番つきの区分にする(無い値は空になり、後ろに並ぶ)
    kubun = pd.Categorical(s.where(s.isin(junban)), categories=junban, ordered=True)
    return pd.Series(kubun, index=s.index)


narabi = chumon.sort_values("サイズ", key=jun, kind="stable")
print(narabi.to_string(index=False))
narabi.to_excel("chumon_narabi.xlsx", index=False)

関数junが返す区分は並べる順番を決めるためだけに使い、表のサイズの列はそのまま残ります。kind="stable"は、同じサイズの行を読み込んだ順のまま並べるための指定です。Excelのファイルを開いて保存するところは、pandasの中でopenpyxlが受け持つので、あわせて入れておきます。

試した結果

注文番号・地域・サイズの3列で、データの行が20行の架空の注文の一覧で動かしました。サイズは小5行・中6行・大6行のほか、順番の一覧に無いLLが1行、末尾に空白の入った「大 」が1行、空欄が1行です。

  • 「順番に無い値の行: [['C-06', 'LL'], ['C-13', '大 '], ['C-17', nan]]」と表示されました
  • 並んだ表の先頭は小の5行で、注文番号はC-02・C-07・C-10・C-15・C-19と、読み込んだ順のままでした
  • 小の後に中の6行、大の6行が続き、最後にLL・「大 」・空欄の3行が並びました
  • chumon_narabi.xlsx は3列・20行で、LLと「大 」もそのままの値で書き出されていました
  • chumon.xlsx のハッシュ値は、動かす前と後で変わっていませんでした

動かしたのは手元のMacで、pandasは3.1.1、Pythonは3.12.15、openpyxlは3.1.5です。書き出した表は、openpyxlで開き直して中身を見ました。Excelのアプリでは開いていません。

順番の一覧を自分で決めてよいか、相談するかの判断

目安は、「その順番が、表を読む人のあいだで決まっているかどうか」です。サイズの小・中・大のように誰が見ても同じ順番なら、コードの一覧に書いて使ってかまいません。

地域や部署の並びのように、資料ごとに順番が違うことがある場合は、先に表を読む人と並びを決めておきます。新しい値が増えたとき(サイズにLLが加わる、支店が増えるなど)は、一覧に無い値の行が画面に出るので、そのときにどこへ入れるかを相談します。

つまずきやすいところ

  • ふつうに並べると、思った順番にならない: keyを付けずにsort_valuesで並べると、先頭がLLで、その後に中・大・小の順になりました。文字の番号の小さい順に並ぶためで、小・中・大の意味は使われません
  • 列そのものを区分に変えると、値が消える: サイズの列をそのまま順番つきの区分に変えると、LLと「大 」が空になり、書き出したファイルからも値が消えました。3.1.1では、非推奨の警告も出ました。列は変えずに、keyの関数の中だけで区分にします
  • 末尾の空白で、順番に無い値になる: 「大 」は「大」と別の値として扱われ、一覧に無い行として最後に並びました。空白を取ってから並べる手順は、文字の前後の空白と全角・半角をそろえる記事にあります
  • 同じ値の行の並びが崩れる: kindを付けないと、小の5行の先頭がC-10になり、読み込んだ順が崩れました。kind="stable"を付けると、C-02から順に並びました
  • 逆に並べても、一覧に無い行は後ろのまま: ascending=Falseで大・中・小の順になっても、LL・「大 」・空欄の3行は最後に残りました。先頭に出すときは、na_position="first"を付けます
  • 値の大きい順に並べたい: 売上や点数のような数の列なら、順番の一覧は要りません。PythonでExcelの表を並べ替えて上位の行を取り出す手順のsort_valuesだけで並びます
  • 曜日の順に並べたい: 日付から曜日を出して月曜から並べるなら、曜日の番号を使うPythonでExcelの日付から曜日ごとの合計を出す手順のやり方もあります

まとめ

  • 決めた順番で並べるには、順番の一覧から作った順番つきの区分を、sort_valuesのkeyで渡します
  • 列の値は変えずに、keyの関数の中だけで区分にすると、一覧に無い値も残ります
  • 一覧に無い値と空欄は後ろに並ぶので、並べる前にisinで確かめます
  • 同じ値の行を読み込んだ順に保つには、kind="stable"を付けます