この記事でわかること

  • Excelの1つの列に入った文字を、pandasのstr.splitで2つの列に分ける方法
  • 分ける回数(n)と、できる列の数の関係
  • 区切りが無い行や、空白が2つ以上ある行の扱い
  • 分けた列を足して、別のExcelのファイルに保存する手順

名簿の「氏名」の列に「山田 太郎」のように姓と名が続けて入っていると、姓だけで並べ替えたり、ほかの表の姓の列とつなげたりするときに困ります。1件ずつ手で切り分けるのは時間がかかり、写しまちがいも起きます。ここでは、Pythonのpandasを使って、空白を区切りにして1つの列を姓と名の2つの列に分け、新しいファイルに残すところまでを、順を追って見ていきます。記事用に用意した架空の名簿でコードを動かし、出てきた結果もあわせて紹介します。

str.splitの指定の意味は、pandasの公式の資料にあたって確認しました(APIリファレンスとユーザーガイド、確認日は2026年10月25日)。名簿は架空のもので、実在の人の名簿は使っていません。

先に結論: str.splitにexpand=Trueとn=1を付けて2つの列にする

先に結論を書くと、1つの列を2つに分けるときは、str.splitに区切りの文字を渡し、expand=Trueで列に分け、n=1で最初の区切りだけで分けます。 よく使う指定は、次の4つです。

指定 役割
pat 区切りの文字
n 分ける回数の上限
expand 列に分けるか
regex 正規表現として扱うか

str.splitで1つの列を区切りで分ける

pandasのstr.splitは、列の中のそれぞれの文字を、指定した区切りの文字で前から分ける働きをします。区切り(pat)を指定しないときは、空白で分けます。

初期の設定(expand=False)では、結果は1つの列のままで、セルごとに分けた文字のリストが入ります。expand=Trueを付けると、分けた文字が別々の列に入った表(DataFrame)になります。ユーザーガイドの例でも、空欄(NaN)のセルは、分けた後も空欄のままです。

区切りに1文字を渡すと、そのまま文字として扱われます。資料によると、regexを付けないときは、区切りが1文字なら文字として、2文字以上なら正規表現として扱うとしています。

分ける回数とできる列の数

nは、分ける回数の上限です。初期の設定では、区切りが見つかるたびにすべて分けます。n=1にすると最初の区切りだけで分け、残りは後ろの列にまとめて入ります。

expand=Trueのときにできる列の数は、すべての行のうち最も多く分けられた回数に1を足した数です。分けられた回数がほかの行より少ない行は、足りない列が空になります。資料には、nは上限であって列の数を決めるものではないため、列の数をそろえたいときは結果をreindexするとよい、とも書かれています。

手順: 氏名の列を姓と名に分けて別のファイルに保存する

次のコードは、架空の名簿 members.xlsx(社員番号と氏名の2列)を読み込み、氏名の列を最初の空白で分けて、姓と名の2つの列を表の右に足します。結果は新しいファイル(members_split.xlsx)として保存し、元のmembers.xlsxは書き換えません。自分の名簿で試すときは、列名とファイル名をその表に合わせ、作業の前に元のファイルの控えを取っておきます。

import pandas as pd

# 元の名簿を読み込む(このファイルは書き換えない)
src_file = "members.xlsx"
df = pd.read_excel(src_file)

# 全角の空白を半角にそろえ、最初の空白だけで2つの列に分ける
names = df["氏名"].str.replace(" ", " ").str.split(" ", n=1, expand=True)

# 空白が無い行しか無くても2列になるように、列を0と1にそろえる
names = names.reindex(columns=[0, 1])
df["姓"] = names[0]
df["名"] = names[1]
print(df)

# 姓と名の列を足した表を、別の名前で保存する
out_file = "members_split.xlsx"
df.to_excel(out_file, index=False)

実行する前に、pandasと、新しい形式のExcelのファイル(xlsx)を扱うopenpyxlを入れておきます。氏名の列には全角の空白で区切った行が混ざることがあるため、分ける前にstr.replaceで半角の空白に置き換えています。reindexの行は、資料にある列の数のそろえ方に沿ったものです。元の氏名の列は残したまま、姓と名の列を足しています。

実行した結果

6人分の架空の名簿(半角の空白で区切った行、全角の空白で区切った行、空白の無い行、氏名が空欄の行、空白が2つある行を含む)で試したところ、次のようになりました。

  • 社員番号・氏名・姓・名の4列、6行の表になりました
  • 「山田 太郎」「鈴木 花子」は、姓と名にそのまま分かれました
  • 全角の空白で区切った「田中 一郎」も、姓が田中、名が一郎に分かれました
  • 空白の無い「佐藤」は姓が佐藤、名が空になり、氏名が空欄の行は姓も名も空になりました
  • 空白が2つある「渡辺 マリア 恵」は、姓が渡辺、名が「マリア 恵」になりました
  • 保存したmembers_split.xlsxを開くと、4列の見出しの下に6行が並んでいました。読み込んだ元のmembers.xlsxは、実行の前と同じままでした

動かしたのは Mac の作業PCで、Python 3.12.15、pandas 3.0.6、openpyxl 3.1.5 の組み合わせです。

自分で直すか、相談するかの判断

うまく分けられたかは、「名が空になった行」と「名の中に空白が残った行」を数えて見分けます。架空の名簿では、名が空の行が2行(空白の無い行と空欄の行)、名に空白が残った行が1行でした。これらの行は、元の氏名を見て、手で直すか、そのままにするかを決めます。氏名が空欄の行を先に洗い出したいときは、PythonでExcelの表の空欄を見つけて一覧にする手順のやり方が使えます。

どこまでが姓でどこからが名かは、文字だけでは決められないことがあります。名前の途中に空白がある人や、姓と名の順が逆に入っている行があるときは、プログラムで分けた結果を正しいと決めつけず、名簿を管理している人に確かめます。

つまずきやすいところ

  • expand=Trueを付け忘れる: 1つの列のまま、セルにリストが入ります。架空の名簿では、そのまま書き出すと「['山田', '太郎']」のような文字列がセルに入りました
  • nを付けずに分ける: 「渡辺 マリア 恵」の行が3つに分かれ、列が3つになりました。0と1の列だけを使うと、「恵」が抜け落ちます
  • 全角の空白が混ざっている: 置き換えをしないで分けると、「田中 一郎」は分かれず、名が空になりました。空白や全角・半角をまとめてそろえる方法は、PythonでExcelの表の文字の前後の空白と全角・半角をそろえる手順が参考になります
  • どの行にも区切りが無い: 架空の2人分の名簿(「佐藤」「高橋」)で試すと、列が1つしかできず、1の列を取り出そうとしたところでKeyErrorで止まりました。記事のコードのreindexの行は、これを防ぐためのものです
  • 区切りに2文字以上を渡す: regexを付けないと正規表現として扱われます。架空の文字「A..B」を「..」で分けると、「..」が任意の2文字として扱われ、空の文字が3つ並んだだけになりました。regex=Falseを付けると、AとBに分かれました
  • 分けた列でほかの表とつなぐとき: 姓などの列を使ってほかの表とつなげる手順は、PythonでExcelの2つの表を共通の列で結合する手順にあります。分けた後の文字の前後に空白が残っていないかを先に確かめます

まとめ

  • 1つの列を2つに分けるときは、str.splitにexpand=Trueを付け、n=1で最初の区切りだけで分けます
  • 全角の空白が混ざる列は、分ける前に半角にそろえます
  • どの行にも区切りが無くても2列になるように、reindexで列をそろえます
  • 名が空の行や、名に空白が残った行を数えて確かめ、結果は新しいファイルとして保存して元の表は残します