Courses
社内データベースから新しいCSVを取り出してdf.head()を実行すると、CUST_ID_NBR、txn_amt_usd_2、Unnamed: 7、あるいはCustomer Name (Full)のような列が見つかることがあります。さらに、末尾にスペースがあり、KeyErrorで午後が台無しになるまで気づかないこともあります。乱雑な列名は実データ作業でよくある小さな摩擦であり、本格的な分析に入る前に最初に行うのが、pandasでの列名変更ステップです。
このpandasで列名を変更するチュートリアルでは、次の内容を学びます。
-
.rename()で特定の列または複数列をリネームする -
df.columnsや.set_axis()で全列名を一括置換する -
関数を適用して名前を一括変換する
-
.strアクセサで乱れた名前をクリーニングする -
pd.read_csv()内で読み込み時に列名を変更する -
同じ作業をPolarsで行う方法
-
KeyErrorやValueError: Length mismatchを避ける
このチュートリアルでは、pandasをインポートし、DataFrameを作成できることを前提とします。顧客レコード、売上エクスポート、センサー計測といった現実的なデータセットを通して、実務データにそのまま当てはまるパターンを扱います。
どのPandasのリネーム方法を選ぶべきか?
タスクの範囲に合う方法を選んでください。狙い撃ちのリネーム、全置換、または全ての名前に規則を適用する方法です。
|
目的 |
方法 |
適する場面 |
|
特定の列を1つまたは数個だけリネームする |
|
他の列はそのまま維持。メソッドチェーン内でも安全 |
|
全ての列名を置き換える |
|
各名前をマッピングするより速い。チェーンしたい場合は |
|
規則でリネーム(lowercase、snake_case、strip) |
|
全列を列挙せず、規則を一度だけ表現できる |
|
読み込み時にリネーム |
|
スキーマを自分で管理し、別ステップを設けたくない場合 |
|
Polarsで上記すべて |
|
イミュータブルかつチェーン優先のため、 |
.rename()で列名を変更するには?
.rename()は、pandasのDataFrameで列名を変更する最も柔軟な方法であり、最も頻繁に使うアプローチです。
古い名前から新しい名前への対応をディクショナリで渡すと、指定しなかった列はそのまま残り、既定では元のDataFrameを変更せず新しいDataFrameを返します。これにより、.rename()はメソッドチェーン内で安全に使え、デバッグ時の見通しも良くなります。
ディクショナリのパターンは次のようになります。
sales_data.rename(columns={"old_name": "new_name"})
ディクショナリに不慣れな場合は、Pythonのディクショナリメソッドのチュートリアルで復習するとよいでしょう。
旧来のcopyパラメータについて
実例に入る前に一点。Pandas 3.0ではcopyパラメータが非推奨となり、Copy-on-Writeがデフォルトになりました。実務上は、.rename()が高コストなコピーを作るかどうかを気にする必要がなくなったということです。コピーは内部で遅延的に処理されます。検討すべき主なパラメータはinplaceだけになりました。これは3つ目のサブセクションで扱います。
単一の列をリネームする
レガシーCRMからエクスポートされた顧客レコードを読み込んだ場面を想像してください。2008年にデータベースを設計した誰かには意味が通ったであろう省略形の列名ですが、今の自分には分かりにくい。これは最も単純なpandasの列名変更で、古い名前1つと新しい名前1つをディクショナリで指定します。
import pandas as pd
customers = pd.DataFrame({
"cust_id_nbr": [4521, 4522, 4523, 4524],
"first_nm": ["Abe", "Rick", "Pat", "Kim"],
"signup_dt": ["2008-03-12", "2008-03-15", "2008-03-18", "2008-03-21"]
})
print(customers)

では、cust_id_nbrをより読みやすい名前に変更します。
customers_renamed = customers.rename(columns={"cust_id_nbr": "customer_id"})
print(customers_renamed)

元のcustomers DataFrameは変更されていません。.rename()は新しいDataFrameを返し、それをcustomers_renamedに代入しました。指定しなかった2列(first_nm、signup_dt)はそのまま引き継がれます。
複数列をリネームする
ディクショナリは自然に拡張できます。複数列のリネームは、マッピングにキーと値の組を追加するだけです。
customers_clean = customers.rename(columns={
"cust_id_nbr": "customer_id",
"first_nm": "first_name",
"signup_dt": "signup_date"
})
print(customers_clean)

columnsキーワードの代わりに、mapperとaxis引数を使う別構文もあります。
customers.rename(mapper={"cust_id_nbr": "customer_id"}, axis=1)
axis=1は列(行インデックスラベルのaxis=0ではなく)を対象にすることを示します。どちらも同じ結果になります。実務のコードでは一目で分かりやすいcolumns={...}がよく使われるため、本チュートリアルでもこのパターンを用います。
便利なポイントとして、既定では存在しない列名をキーに渡しても、.rename()は黙って無視します。これは、やや異なるスキーマのDataFrameを扱う再利用可能な関数を書くときに便利ですが、タイプミスを見逃す原因にもなります。未知の列名で例外を出すには、errors='raise'を渡してください。
inplaceを使うか、新しいDataFrameを返すか
既定では、.rename()は新しいDataFrameを返し、元のものは変更しません。既存のDataFrameを直接変更したい場合は、inplace=Trueを渡します。
# 新しいDataFrameを返す(デフォルト)
customers_v2 = customers.rename(columns={"first_nm": "first_name"})
# customersを直接変更し、Noneを返す
customers.rename(columns={"first_nm": "first_name"}, inplace=True)
print(customers)

ではどちらを使うべきでしょうか。多くの場合は、新しいDataFrameを返す既定の挙動のほうが適しています。何か問題が起きたときに元のDataFrameを見られるため、デバッグも容易です。また、古いコードで発生するSettingWithCopyWarningに関わるエイリアシング問題も回避できます。
パフォーマンスの観点でも、今はinplaceを選ぶ理由はほとんどありません。pandas 3.0+ではCopy-on-Writeがデフォルトになり、非inplace版は遅延コピーを行います。実際にデータが変更されるまで複製は行われません。inplace=Trueがメモリ節約になるという従来の主張は、以前ほど強くありません。
inplace=Trueがしっくりくるのは、短い試行的スクリプトで単一のDataFrameを段階的にクリーンアップしていて、チェーンを気にしない場合くらいです。プロダクションコードや後で見直す可能性があるものでは、既定を選ぶのがおすすめです。
pandasで全列名を一度に変更するには?
古い名前から新しい名前への対応を作りたくない場合もあります。全ての列名を一括で置き換えたいときです。これは意外とよく起きます。例えば、ヘッダーがないCSVでpandasが0, 1, 2のような列名を割り当てた場合、ヘッダー行が別言語のデータセット、Field1、Field2、Field3のようにシステム生成された名前のエクスポートなどです。
一般的な方法は2つあります。df.columnsに直接代入するか、.set_axis()を使う方法です。結果は同じで、簡潔さとチェーン可能性のトレードオフになります。
df.columnsにリストを代入する
最も直接的なのは、columns属性に新しいリストを代入する方法です。以下はヘッダー情報のないリストのリストから構築したDataFrameで、ヘッダーレスCSVを読んだときによくある形です。pandasは整数の列名にフォールバックします。
import pandas as pd
sensor_readings = pd.DataFrame([
[1.2, 22.5, 1013],
[1.5, 22.7, 1012],
[1.3, 22.6, 1013]
])
print(sensor_readings)

この0、1、2という列名は分析には役立ちません。columns属性に新しいリストを代入して置き換えます。
sensor_readings.columns = ["wind_speed", "temperature_c", "pressure_hpa"]
print(sensor_readings)

この方法で知っておくべきことは2点あります。
-
リストの長さは厳密に一致する必要があります。4列のDataFrameに3つの名前を渡すと、pandasは
ValueError: Length mismatchを投げます(このエラーは後ほど詳しく扱います)。 -
これはDataFrameを直接変更します。ここには
inplaceパラメータはなく、代入自体が変更です。新しいコピーが必要なら、先に.copy()を使うか、後述の.set_axis()を選びます。
メソッドチェーンには.set_axis()を使う
.set_axis()は同じことを行いますが、新しいDataFrameを返すため、他の操作とチェーンできます。今度は桁数が多かったり欠損があるなど、もう少し乱れたデータを想定したヘッダーレスのDataFrameを考えます。
raw_sensor = pd.DataFrame([
[1.234, 22.567, 1013],
[1.512, 22.789, 1012],
[None, 22.601, 1013],
[1.345, 22.612, 1013]
])
sensor_clean = (
raw_sensor
.set_axis(["wind_speed_mps", "temp_celsius", "pressure_hpa"], axis=1)
.round(1)
.dropna()
)
print(sensor_clean)

axis=1は列ラベルを設定していることを示します(行インデックスの設定はaxis=0)。.set_axis()は新しいDataFrameを返すため、実際のETLや分析コードで書くような変換のパイプラインに自然に組み込めます。これが、プロダクションでは直接代入よりもこちらを好む主な理由です。
pandasで関数を使って列名を変更するには?
古い名前から新しい名前への対応を列挙する代わりに、.rename()へ関数を渡すと、全ての列名にその関数が適用されます。リストではなく規則で処理したいときに最適です。たとえば「すべて小文字にする」や「空白をアンダースコアに置き換える」といったものです。
組み込みの文字列関数を使う
最も単純なのは大文字小文字の標準化です。str.lower、str.upper、str.titleをcolumns引数へ直接渡します。
import pandas as pd
orders = pd.DataFrame({
"Order ID": [1001, 1002, 1003],
"Customer Name": ["Abe", "Rick", "Pat"],
"Total Amount": [49.99, 120.00, 75.50]
})
orders_lower = orders.rename(columns=str.lower)
print(orders_lower.columns.tolist())
![]()
渡しているのは関数本体(str.lower)であり、呼び出し(str.lower())ではない点に注意してください。pandasは各列名に順番に適用します。これはケース標準化の近道ですが、空白や特殊文字は処理しません。その場合はlambdaやカスタム関数を使います。
lambdaやカスタム関数を使う
大文字小文字の変更を超える処理には、lambdaでインラインに変換を表現するのが手早いです。lambdaに不慣れなら、Pythonのlambda関数入門ガイドを参照してください。
よくあるパターンは、小文字化して空白をアンダースコアに置換するワンステップです。先ほどの例を使います。
orders_snake = orders.rename(columns=lambda col: col.lower().replace(" ", "_"))
print(orders_snake.columns.tolist())
![]()
ロジックが複雑になってきたら、名前付き関数に切り出しましょう。camelCaseやPascalCaseの列名をsnake_caseに変換するヘルパーを考えます。
import re
def to_snake_case(name: str) -> str:
"""Convert camelCase or PascalCase to snake_case."""
s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name)
s2 = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1)
return s2.lower()
api_response = pd.DataFrame({
"userId": [1, 2, 3],
"firstName": ["Abe", "Rick", "Pat"],
"accountCreatedAt": ["2024-01-01", "2024-01-02", "2024-01-03"]
})
api_clean = api_response.rename(columns=to_snake_case)
print(api_clean.columns.tolist())
![]()
このような名前付き関数は、巧妙なワンライナーよりもテストやノートブック間の再利用、ドキュメント化がしやすくなります。ロジックが1行に収まるならlambda、そうでなければカスタム関数を選びましょう。
pandasで乱れた列名を一括でクリーンアップするには?
スプレッドシート、サードパーティAPI、手編集のCSVから届くデータでは、.rename()だけではうまく直しづらい問題を列名が抱えていることがよくあります。具体的には次のようなものです。
- 末尾の空白
- 大文字小文字が混在
- 括弧
- ハイフン
- 特殊文字
- 見えないUnicode文字
こうした状況では、.strアクセサを使ってdf.columnsを直接操作するのが最もクリーンです。これは(正規表現を含む)ベクトル化された文字列メソッドを全列名に一度に適用できます。これは堅牢なPythonでのデータクリーニングの基礎でもあります。列名をクリーンにすると、その後のフィルタリング、結合、可視化といったステップのエラーが減ります。
空白や特殊文字を取り除く
多くの人の手を経たExcelエクスポートでありがちな列名を持つDataFrameを例に取ります。
import pandas as pd
raw_export = pd.DataFrame({
" Order ID ": [1001, 1002, 1003],
"Customer Name (Full)": ["Abe", "Rick", "Pat"],
"Total Amount ($)": [49.99, 120.00, 75.50],
"Order-Date": ["2024-03-12", "2024-03-15", "2024-03-18"]
})
print(raw_export.columns.tolist())
![]()
最も一般的で厄介なのは、目に見えない先頭・末尾の空白です。これは1行で取り除けます。
raw_export.columns = raw_export.columns.str.strip()
print(raw_export.columns.tolist())
![]()
特殊文字には.str.replace()で正規表現パターンを使えます。以下のパターンは、英数字とアンダースコア、空白を残し、それ以外を削除します。
raw_export.columns = raw_export.columns.str.replace(r"[^a-zA-Z0-9_ ]", "", regex=True)
print(raw_export.columns.tolist())
![]()
ハイフン、括弧、ドル記号がなくなりました。Total Amountには(($)があった場所に)末尾の空白が残り、OrderDateはハイフンが完全に失われました。だからこそ、クリーニングの最後にもう一度stripするのが定石です。
snake_caseに標準化する
分析を始める前に全列名をsnake_caseにするのは一般的なベストプラクティスです。すなわち小文字、単語はアンダースコアで区切り、特殊文字なし。.strメソッドをチェーンして、1つの式で到達します。
raw_export = pd.DataFrame({
" Order ID ": [1001, 1002, 1003],
"Customer Name (Full)": ["Abe", "Rick", "Pat"],
"Total Amount ($)": [49.99, 120.00, 75.50],
"Order-Date": ["2024-03-12", "2024-03-15", "2024-03-18"]
})
raw_export.columns = (
raw_export.columns
.str.strip() # 前後の空白を除去
.str.lower() # すべて小文字に
.str.replace(r"[^a-z0-9]+", "_", regex=True) # 英数字以外をアンダースコアに畳み込み
.str.strip("_") # 先頭・末尾のアンダースコアを除去
)
print(raw_export.columns.tolist())
![]()
わずか4行で、列名は予測可能で小文字、アンダースコア区切りになります。このパターンはユーティリティ関数として保存する価値があります。ひとたび用意しておけば、手元に来る乱れたDataFrameにいつでも適用できます。
列名変更と列の削除を組み合わせたい場面も多いはずです。その場合は、pandasで列を削除するチュートリアルが次のステップをカバーします。
pandasで読み込み時に列名を変更するには?
ファイルを読み込む前から列名を変えたいことが分かっているなら、pd.read_csv()の中で直接リネームできます。namesパラメータに名前のリストを渡し、header=0を設定して、既存のヘッダー行をスキップし、指定した名前を使うようpandasに伝えます。
import pandas as pd
from io import StringIO
# デモ用にCSVファイルをシミュレート
csv_data = """txnId,custId,amt,date
1001,C01,49.99,2024-01-15
1002,C02,125.00,2024-01-16
1003,C01,79.50,2024-01-17"""
# 読み込み時に列名を置換し、元のヘッダーをスキップ
transactions = pd.read_csv(
StringIO(csv_data),
header=0,
names=["transaction_id", "customer_id", "amount_usd", "transaction_date"]
)
print(transactions)

スキーマを自分で管理していて、読み込みコードに.rename()の別ステップを増やしたくないときに便利な近道です。ヘッダー行がまったくないファイルなら、header=0は指定せず、names=[...]だけで一から列名を割り当てます。読み込みオプションをより深く知るには、pandas read_csv()のチュートリアルをおすすめします。
注意点が1つ。これは全置換のアプローチです。namesパラメータは全ての列名を置き換えるため、リストの長さはファイル内の列数と正確に一致する必要があります。数列だけ変更したいなら、まず読み込んでから.rename()を使ってください。
これらのパターンを他の一般的なクリーンアップ作業と併せて実践的に学ぶには、Cleaning Data in Pythonコースをぜひ受講してください。
Polarsとpandasでの列名変更の違い
pandasとPolarsの両方を使っている、または今後使う予定があるなら、各ライブラリの列名変更の扱いを知っておく価値があります。高レベルAPIは似ていますが、細部が異なり、最初は戸惑いやすい点があります。Polarsは高速なRust製バックエンドのDataFrameライブラリで、近年のデータ基盤で一般的になりつつあります。pandasで身につけた筋メモリがそのまま移植できるとは限りません。
基本的な考え方は同じです。古い名前から新しい名前へのディクショナリを渡します。違いは詳細にあります。Polarsは設計上イミュータブル(inplaceなし)で、メソッドチェーンが慣用的スタイルです。また、select中の列レベルのリネームには、別のrenameステップではなく.alias()を使います。
サイドバイサイドの比較
|
タスク |
Pandas |
Polars |
|
特定の列をリネーム |
|
|
|
全列名を置換 |
|
|
|
select中にリネーム |
まずselectし、その後 |
|
|
インプレース変更 |
|
非対応。常に新しいDataFrameを返す |
|
慣用的スタイル |
|
常にチェーン |
同じリネームを両ライブラリで
比較のため、それぞれのライブラリでのシンプルなリネームを示します。
Pandas:
# Pandas
import pandas as pd
orders_pd = pd.DataFrame({
"ord_id": [1001, 1002, 1003],
"cust_nm": ["Abe", "Rick", "Pat"]
})
orders_pd = orders_pd.rename(columns={"ord_id": "order_id", "cust_nm": "customer_name"})
print(orders_pd)

Polars:
# Polars
import polars as pl
orders_pl = pl.DataFrame({
"ord_id": [1001, 1002, 1003],
"cust_nm": ["Abe", "Rick", "Pat"]
})
orders_pl = orders_pl.rename({"ord_id": "order_id", "cust_nm": "customer_name"})
print(orders_pl)

注目すべき小さな違いが2つ。Polarsの.rename()はディクショナリをそのまま受け取ります。Polarsは列(行インデックスなし)のリネームだけをサポートしているため、columns=キーワードはありません。そして結果を再代入する必要があります。Polarsにはinplace=Trueがなく、すべての操作が新しいDataFrameを返します。
Polarsの出力は、先頭にshape、各列にdtypes(i64、str)が併記されるのも特徴で、乗り換えると小気味よく感じる点です。
select中に列名を変更する
変換の途中でのリネームは、Polarsでは.select()や.with_columns()内の.alias()を使います。
# Polars
import polars as pl
orders_pl = pl.DataFrame({
"ord_id": [1001, 1002, 1003],
"cust_nm": ["Abe", "Rick", "Pat"]
})
# Selectとリネームを1つの式で
renamed = orders_pl.select(
pl.col("ord_id").alias("order_id"),
pl.col("cust_nm").alias("customer_name")
)
print(renamed)

pandasでは、列選択のあとに.rename()を行うのが相当します。どちらが優れているという話ではなく、各ライブラリの設計思想の違いを反映しています。
より詳しい比較が必要であれば、 pandasとpolarsのパフォーマンス比較チュートリアルをおすすめします。さらにpolarsを学ぶなら、Introduction to Polars コースがおすすめです。
よくあるエラーと対処法
pandasの列名変更で繰り返し遭遇するエラーが2つあります。どのような見た目か、なぜ起きるか、どう直すかを説明します。
KeyError: 列名が見つからない
既定では、.rename()は一致しないキーを黙って無視します。しかしタイプミスを検出したいときにerrors='raise'を渡すと、存在しないキーでKeyErrorが発生します。
import pandas as pd
orders = pd.DataFrame({
"order_id": [1001, 1002, 1003],
"customer_name": ["Abe", "Rick", "Pat"]
})
# これはエラーを投げる
orders.rename(columns={"Order_ID": "order_id"}, errors="raise")
![]()
最も多い原因は、大文字小文字の取り違え(Order_IDとorder_id)や、見えない末尾の空白("order_id "と"order_id")です。KeyErrorに遭遇したら、次の3点をこの順で確認してください。
- 綴りと大文字小文字が正確か
- 隠れた空白がないか
- その列がすでに前段でリネームされていないか
実際の列名を確認するには次のようにします。
print(orders.columns.tolist())
# 代わりにrepr()を使う方法
print([repr(c) for c in orders.columns])
![]()
pandasが保持している正確な文字列が分かれば、たいていタイプミスは明らかです。綴りを直して再実行します。
orders = orders.rename(columns={"order_id": "Order_ID"}, errors="raise")
print(orders.columns.tolist())
![]()
では、いつerrors='raise'を使い、いつ既定のerrors='ignore'を使うべきでしょうか。
-
既定は寛容です。スキーマが変動するDataFrameを処理するスクリプトで、列が欠けていても停止させたくない場合に役立ちます。
-
開発時にタイプミスを早めに顕在化させたい場合、とくにサイレントな失敗が後工程で長いデバッグを招くノートブックでは、
errors='raise'に切り替えましょう。
ValueError: df.columnsで長さが一致しない
df.columnsにリストを代入する、または.set_axis()を使う場合、リストの長さは列数と厳密に一致する必要があります。一致しないと、pandasはValueErrorを投げます。
import pandas as pd
products = pd.DataFrame({
"sku": ["A100", "A101", "A102"],
"name": ["Widget", "Gadget", "Gizmo"],
"price": [9.99, 14.99, 19.99]
})
# これはエラーになる
products.columns = ["product_sku", "product_name"]
![]()
DataFrameは3列あるのに、新しい名前は2つしか渡されていません。修正するには、代入前に列数を確認します。
print(len(products.columns))
products.columns = ["product_sku", "product_name", "product_price"]
print(products.columns.tolist())
![]()
列数が変動し得るDataFrameを扱うなら、ディクショナリを使った.rename()のほうが安全です。指定した列だけに作用するため、列が欠けたり余分でもコードが落ちません。
まとめ
pandasでの列名変更は、タスクの範囲に合った方法を選ぶことに尽きます。どのアプローチを選ぶにせよ、最大の実用的なメリットは、単一の命名規則に統一し、分析の最初のステップとして適用することです。Pythonではsnake_caseが一般的です。列名を整えるのに数秒かけることで、プロジェクトの残りの期間でKeyErrorの不意打ちから解放されます。
狙い撃ちのリネームにはディクショナリを使った.rename()を使いましょう。全列を新しい名前にするなら、df.columnsへの代入や.set_axis()のほうが、全ての旧名から新名へのマップを作るより速いです。空白の削除や小文字化、camelCaseの変換など規則に従うなら、関数を渡すか.strアクセサを使って、列挙ではなく規則を一度だけ表現できます。Polarsでも似たAPIで同じ作業ができますが、イミュータブルでチェーン優先のスタイルが、少し異なる習慣へと導きます。
DataFrameスキルをさらに伸ばすなら、次のステップとしてData Manipulation with pandasコースがおすすめです。体系的に学びたい場合は、Data Analyst in Pythonキャリアトラックで、DataFrame操作とアナリストの必須ツール群を並行して身につけられます。
pandasの列名変更に関するFAQ
pandasで列名を変更するには?
いくつか方法がありますが、最も分かりやすいのは df = df.rename(columns={"old_name": "new_name"}) を使うことです。既存のDataFrameを直接変更したい場合は、inplace=Trueを渡します。
pandasで複数の列名を変更するには?
複数列をリネームするには、すべての変更を1つのディクショナリで渡します:df.rename(columns={"old1": "new1", "old2": "new2"})
pandasのDataFrameで全ての列名を変更するには?
新しい名前のリストをdf.columnsに代入します。注意:リストの長さが列数と一致していないとValueErrorになります。
df.rename()でDataFrameが変わらないのはなぜ?
既定では、.rename()は新しいDataFrameを返します。結果をdf = df.rename(...)のように代入し直すか、inplace=Trueを使ってください。
pandasで列名を小文字にするには?
全ての列名を一度に小文字化するには、df.columns = df.columns.str.lower()を使います。