pandas 列名 (カラム名) 変更 ガイド【初心者歓迎】


Pandas 列名 (カラム名) 変更 ガイド【初心者歓迎】

データ分析の世界へようこそ!特にPythonを使ったデータ分析では、pandasライブラリが非常に重要な役割を果たします。pandasを使うと、Excelのような表形式のデータを簡単に扱えるようになります。この表形式のデータは「DataFrame」と呼ばれ、データ分析の強力な味方です。

さて、データ分析を始めるにあたって、まず最初に直面することが多いのが「列名」(カラム名)の扱いです。データファイルを開いてみたら、列名が「Unnamed: 0」となっていたり、全角スペースが含まれていたり、あるいは日本語で書かれていて、後続の処理で扱いにくかったり…。このような状況は日常茶飯事です。

この記事では、pandas DataFrameの列名(カラム名)を思い通りに変更する方法を、初心者の方にも分かりやすく、そして徹底的に解説します。なぜ列名変更が必要なのか、どのような方法があるのか、それぞれの方法のメリット・デメリット、具体的なコード例、さらにはよくある疑問やトラブルシューティングまで、これ一本でマスターできるような内容を目指します。

さあ、pandasを使ったデータ操作の第一歩として、列名変更のスキルをしっかりと身につけましょう!

1. はじめに:PandasとDataFrame、そして列名の重要性

Pandasとは?

Pandasは、Pythonプログラミング言語用のオープンソースライブラリです。データ分析、操作、クリーニング、前処理などを効率的に行うためのデータ構造とツールを提供します。特に、表形式のデータ(Excelやデータベースのようなデータ)を扱うのに長けています。

DataFrameとは?

Pandasの最も重要なデータ構造の一つが「DataFrame」です。DataFrameは、列指向のスプレッドシートやSQLテーブルのような2次元のラベル付きデータ構造です。データは行と列で整理されており、各列には名前(ラベル)が付いています。この列の名前が「列名」(またはカラム名)です。

例えば、以下のようなデータがあるとします。

ID 名前 年齢 居住地
1 山田太郎 30 東京都
2 佐藤花子 25 大阪府
3 田中一郎 35 愛知県

これをPandas DataFrameとして扱う場合、「ID」「名前」「年齢」「居住地」が列名になります。

なぜ列名変更が必要なのか?

さて、なぜわざわざ列名を変更する必要があるのでしょうか?いくつかの理由が考えられます。

  • 可読性の向上: データファイルによっては、列名が分かりにくい名前(例: col1, data_field_001)になっていたり、長すぎたり短すぎたりすることがあります。分析者が理解しやすく、チームメンバーにも伝わりやすい名前に変更することで、コードや分析結果の可読性が格段に向上します。
  • 命名規則の統一: 複数のデータソースからデータを取得して結合する場合、それぞれの列名に揺れがあることがよくあります(例: 片方では顧客ID、もう片方ではカスタマーID)。これらを統一することで、データ結合やその後の処理がスムーズになります。
  • 扱いにくい文字の排除: 全角スペース、特殊記号、日本語など、プログラミング上で扱いにくい文字が列名に含まれていることがあります。特に、ドット(.)やスペース()が含まれていると、ドット記法(df.列名)でアクセスできないなど、不便が生じます。これらをアンダースコア(_)に置換したり、ローマ字や英語に変換したりします。
  • データ分析ツールの要件: 一部の分析ライブラリやツールでは、特定の命名規則(例: 全て小文字、スペースなし)が求められることがあります。
  • 不要な情報の削除: 列名にバージョン情報や取得日時など、分析には不要なメタデータが含まれている場合があります。これらを削除してシンプルにします。

このように、列名変更はデータ分析の前処理として非常に一般的かつ重要な作業です。適切な列名は、その後の分析プロセスを効率化し、エラーを防ぎ、結果の解釈を容易にします。

2. 列名の確認方法

列名を変更する前に、まずは現在の列名がどうなっているかを確認する必要があります。Pandas DataFrameの列名は、.columnsという属性に格納されています。

以下のコードで、ダミーのDataFrameを作成し、列名を確認してみましょう。

“`python
import pandas as pd

ダミーデータの作成

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

DataFrameの表示

print(“元のDataFrame:”)
print(df)
print(“-” * 30)

列名の確認

print(“現在の列名:”)
print(df.columns)
print(“-” * 30)

列名のデータ型を確認

print(“列名のデータ型:”)
print(type(df.columns))
“`

実行結果:

“`
元のDataFrame:
社員コード 氏名(フルネーム) 所属部署 年齢 入社日
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01


現在の列名:
Index([‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’], dtype=’object’)


列名のデータ型:

“`

.columnsは、pandas.core.indexes.base.Indexという型のオブジェクトを返します。これはリストのように扱えますが、要素がユニークである必要があるなど、いくつかの特性が異なります。しかし、ほとんどの場合、通常のPythonリストと同じように扱って問題ありません。

この例では、「所属部署 」と「年齢 」の列名の末尾に不要なスペースが入っていることに気づきます。また、「氏名(フルネーム)」のような括弧を含む日本語の列名は扱いにくいかもしれません。これらの列名を、よりシンプルで統一された名前に変更したいと考えます。

次のセクションから、具体的な列名変更の方法を見ていきましょう。

3. 列名変更の主要な方法

Pandasで列名を変更するには、主に以下の3つの方法があります。

  1. .rename() メソッド: 特定の列名だけを変更したい場合や、列名に関数を適用して一括変換したい場合に最も柔軟に使えます。
  2. .columns 属性への直接代入: 全ての列名を新しいリストで置き換えたい場合にシンプルに使えます。
  3. .set_axis() メソッド: .columns 属性への代入に似ていますが、より汎用的なインデックス/カラム名変更に使えます。

これらの方法にはそれぞれ特徴があり、どのような変更を行いたいかによって最適な方法が異なります。順番に詳しく見ていきましょう。

4. .rename() メソッドによる列名変更

.rename() メソッドは、既存のDataFrameに対して、指定した列名(または行インデックス名)を変更するためのメソッドです。特に、一部の列名だけを変更したい場合に非常に便利です。

4.1. 特定の列名だけを変更する(辞書を使う方法)

.rename() メソッドの最も一般的な使い方は、columns 引数に「変更したい現在の列名」をキー、「変更後の新しい列名」を値とする辞書を渡す方法です。

先ほどのダミーデータを使って、「氏名(フルネーム)」を「氏名」に、「所属部署 」を「所属部署」に(末尾のスペースを削除)変更してみましょう。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist()) # リスト形式で表示すると見やすい

rename() メソッドを使って列名を変更

辞書形式で {元の列名: 新しい列名} を指定

new_df = df.rename(columns={
‘氏名(フルネーム)’: ‘氏名’,
‘所属部署 ‘: ‘所属部署’ # 末尾のスペースを削除
})

print(“\n変更後のDataFrame:”)
print(new_df)
print(“\n変更後の列名:”, new_df.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame:
社員コード 氏名 所属部署 年齢 入社日
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘社員コード’, ‘氏名’, ‘所属部署’, ‘年齢 ‘, ‘入社日’]
“`

元のDataFrame dfの列名は変わらず、.rename()メソッドは新しいDataFrame new_dfを返していることに注意してください。'氏名(フルネーム)''所属部署 'だけが指定した新しい名前に変更され、他の列名(’社員コード’, ‘年齢 ‘, ‘入社日’)はそのまま残っています。

4.2. inplace=True オプション

デフォルトでは、.rename()メソッドは新しいDataFrameを返します。元のDataFrameを直接変更したい場合は、inplace=Trueという引数を指定します。

注意: inplace=True を使うと、元のDataFrameが変更され、メソッド自体は None を返します。これは非常に便利なオプションですが、意図せず元のデータを破壊してしまう可能性もあるため、使用には注意が必要です。特に、後で元のデータが必要になる可能性がある場合や、処理の途中で結果を確認しながら進めたい場合は、inplace=Trueを使わずに新しいDataFrameを返す形式 (new_df = df.rename(...)) を使う方が安全です。

先ほどの例を inplace=True を使って書き直してみましょう。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())

rename() メソッドを inplace=True で実行

元の DataFrame (df) そのものが変更される

df.rename(columns={
‘氏名(フルネーム)’: ‘氏名’,
‘所属部署 ‘: ‘所属部署’
}, inplace=True) # ここがポイント!

print(“\n変更後のDataFrame (inplace=True):”)
print(df) # 変数 df の中身が変更されている
print(“\n変更後の列名:”, df.columns.tolist())

ちなみに、inplace=True を使うとメソッドの戻り値は None になる

result_of_rename = df.rename(columns={‘氏名’: ‘名前’}, inplace=True)
print(“\nrename(inplace=True) の戻り値:”, result_of_rename)
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame (inplace=True):
社員コード 氏名 所属部署 年齢 入社日
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘社員コード’, ‘氏名’, ‘所属部署’, ‘年齢 ‘, ‘入社日’]

rename(inplace=True) の戻り値: None
“`

このように、inplace=True を指定すると、明示的に新しい変数に代入しなくても元の df が変更されます。メモリの使用量を抑えたい場合などに有効ですが、多用しすぎるとコードの追跡が難しくなることもあります。筆者の個人的な推奨としては、特別な理由がない限り inplace=True は避け、新しい変数に代入するスタイル (new_df = df.rename(...)) を使う方が、コードの安全性が高く分かりやすいことが多いです。

4.3. 列名に関数を適用して一括変換する

.rename() メソッドのもう一つの強力な使い方が、columns 引数に「関数」を渡す方法です。この関数は、現在の全ての列名を引数として受け取り、変更後の新しい列名を返すように定義します。これにより、特定のパターンに従って全ての列名を一括変換することが可能です。

例えば、全ての列名の前後の空白を取り除きたい、全ての列名を小文字にしたい、スペースをアンダースコアに置換したい、といった場合に便利です。

先ほどのデータで、残っている「年齢 」の末尾のスペースも削除し、さらに全ての列名を英語の小文字に変換してみましょう。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())

列名を一括変換する関数を定義

def clean_and_lowercase(col_name):
# 前後の空白を除去し、小文字に変換
return col_name.strip().lower()

rename() メソッドに関数を渡して列名を変更

cleaned_df = df.rename(columns=clean_and_lowercase)

print(“\n変更後のDataFrame (関数適用):”)
print(cleaned_df)
print(“\n変更後の列名:”, cleaned_df.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame (関数適用):
社員コード 氏名(フルネーム) 所属部署 年齢 入社日
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署’, ‘年齢’, ‘入社日’]
“`

あれ?「氏名(フルネーム)」や「社員コード」、「入社日」は日本語のままで、小文字になっていませんね。これはなぜでしょうか?

理由は、str.lower() メソッドは ASCII アルファベットのみを小文字に変換するためです。日本語などの非ASCII文字には影響しません。

代わりに、もっと一般的な文字クリーニングを行ってみましょう。例えば、全ての列名から不要な空白や括弧を取り除き、さらに日本語の列名はそのまま残しつつ、スペースや特殊記号をアンダースコアに置換する、といった処理を考えます。

“`python
import pandas as pd
import re # 正規表現を使うためにインポート

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())

より複雑なクリーニング関数を定義

def clean_column_name(col_name):
# 1. 前後の空白を除去
cleaned_name = col_name.strip()
# 2. 全角・半角スペース、括弧、その他の特殊記号をアンダースコアに置換
# ここでは例として、スペース、全角スペース、()、()を置換
cleaned_name = re.sub(r'[ \t()()]+’, ‘‘, cleaned_name)
# 3. 連続するアンダースコアを一つにまとめる
cleaned_name = re.sub(r’
{2,}’, ‘‘, cleaned_name)
# 4. 先頭または末尾のアンダースコアを除去 (もしあれば)
cleaned_name = cleaned_name.strip(‘
‘)
# 5. 必要であればここで小文字化などを行う (今回は日本語があるのでスキップ)
# cleaned_name = cleaned_name.lower()
return cleaned_name

rename() メソッドに関数を渡して列名を変更

cleaned_df_v2 = df.rename(columns=clean_column_name)

print(“\n変更後のDataFrame (関数適用 v2):”)
print(cleaned_df_v2)
print(“\n変更後の列名:”, cleaned_df_v2.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame (関数適用 v2):
社員コード 氏名_フルネーム 所属部署 年齢 入社日
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘社員コード’, ‘氏名_フルネーム’, ‘所属部署’, ‘年齢’, ‘入社日’]
“`

今度は意図した通りに列名がクリーニングされましたね。「氏名(フルネーム)」が「氏名_フルネーム」に、「所属部署 」が「所属部署」に、「年齢 」が「年齢」に変更されています。

このように、.rename() メソッドに関数を渡すことで、複雑なルールに基づいた列名の一括変換を柔軟に行うことができます。関数はlambda関数としてインラインで定義することも可能です。例えば、全ての列名に接頭辞 データ_ を付けたい場合は、以下のように書けます。

“`python

ラムダ関数を使った例: 全ての列名に接頭辞を追加

df_prefix = df.rename(columns=lambda col_name: ‘データ_’ + col_name)
print(“\n接頭辞追加後の列名:”, df_prefix.columns.tolist())
“`

実行結果:

接頭辞追加後の列名: ['データ_社員コード', 'データ_氏名_フルネーム', 'データ_所属部署', 'データ_年齢', 'データ_入社日']

関数やラムダ関数を使う方法は、特定の文字の置換、前後の空白除去、大文字/小文字変換など、共通のルールで複数の列名を変更したい場合に非常に役立ちます。

.rename() メソッドのまとめ

  • 用途: 特定の列名だけを変更したい場合、または関数を使って一括変換したい場合。
  • 方法:
    • columns 引数に {元の列名: 新しい列名, ...} の辞書を渡す。
    • columns 引数に列名を変換する関数を渡す。
  • 戻り値: デフォルトでは新しいDataFrameを返す。元のDataFrameを変更したい場合は inplace=True を指定(非推奨の場合が多い)。
  • 利点: 柔軟性が高い。特定の列だけ、またはルールに基づいた一括変更が可能。元の列名が存在しない場合でもエラーにならない(無視される)。
  • 欠点: 全ての列名を変更したい場合は、辞書や関数を用意する必要があり、後述の.columns属性直接代入より少し手間がかかる場合がある。

5. .columns 属性への直接代入による列名変更

Pandas DataFrameの列名は.columnsという属性に Index オブジェクトとして格納されていることを学びました。この.columns属性に対して、新しい列名のリスト(またはIndexオブジェクト)を代入することで、全ての列名を一度に変更することができます。

5.1. 全ての列名を新しいリストで置き換える

この方法を使う場合、代入する新しい列名のリストは、元のDataFrameの列数と完全に一致している必要があります。列数が一致しない場合、エラーが発生します。

先ほどのダミーデータで、全ての日本語の列名を英語の列名に置き換えてみましょう。元の列数は5つなので、新しい列名のリストも5つの要素を持つ必要があります。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())
print(“元の列数:”, len(df.columns))

新しい列名のリストを定義 (元の列数と同じである必要がある)

new_column_names = [‘employee_id’, ‘full_name’, ‘department’, ‘age’, ‘hire_date’]

.columns 属性に新しいリストを直接代入

df.columns = new_column_names # ここがポイント!

print(“\n変更後のDataFrame (.columns 代入):”)
print(df)
print(“\n変更後の列名:”, df.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]
元の列数: 5

変更後のDataFrame (.columns 代入):
employee_id full_name department age hire_date
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘employee_id’, ‘full_name’, ‘department’, ‘age’, ‘hire_date’]
“`

全ての列名が、新しいリストで指定した名前に置き換わりました。この方法は、データファイルを読み込む際に、ファイル自体にはヘッダー行がない場合や、ヘッダー行をスキップして後から自分で列名を付け直したい場合などによく使われます。

5.2. 列数の不一致によるエラー

前述の通り、.columns属性に代入するリストの要素数は、元のDataFrameの列数と完全に一致している必要があります。一致しない場合は、ValueErrorが発生します。

例えば、新しい列名のリストの要素を一つ減らしてみましょう。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df_error = pd.DataFrame(data)

print(“元の列数:”, len(df_error.columns)) # 5列

新しい列名のリスト (4要素、意図的に列数を間違える)

new_column_names_error = [‘id’, ‘name’, ‘dept’, ‘age’] # 要素数が4

try:
# .columns 属性に代入 (エラーになるはず)
df_error.columns = new_column_names_error
except ValueError as e:
print(f”\nエラーが発生しました: {e}”)
print(“新しい列名のリストの要素数が、DataFrameの列数と一致しません。”)

元のDataFrameは変更されていないことを確認

print(“\nエラー発生後の元のDataFrame列名:”, df_error.columns.tolist())
“`

実行結果:

“`
元の列数: 5

エラーが発生しました: Length mismatch: Expected 5, got 4
新しい列名のリストの要素数が、DataFrameの列数と一致しません。

エラー発生後の元のDataFrame列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]
“`

このように、リストの要素数がDataFrameの列数と異なるため ValueError が発生しました。.columns 属性への直接代入は、常に全ての列名を置き換える操作であり、部分的な変更はできません。また、列数の厳密な一致が求められる点に注意が必要です。

5.3. 既存の列名リストを元に新しい列名を生成する

.columns 属性は Index オブジェクトであり、リストのように扱うことができるため、リスト内包表記などを利用して既存の列名リストを加工し、その結果を改めて.columns属性に代入するというテクニックもよく使われます。

これは、前述の.rename()メソッドに関数を渡す方法と似ていますが、.columns属性に代入する場合はDataFrame自体が直接変更されます(inplace=True のようなオプションはありません)。

先ほどの例でやったような、前後の空白除去やスペースの置換を、.columns属性への代入で行ってみましょう。

“`python
import pandas as pd
import re # 正規表現を再度インポート

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())

既存の列名リストを取得し、リスト内包表記と関数で加工して新しいリストを生成

clean_column_name 関数は前述のものを再利用

def clean_column_name(col_name):
# 1. 前後の空白を除去
cleaned_name = col_name.strip()
# 2. 全角・半角スペース、括弧、その他の特殊記号をアンダースコアに置換
cleaned_name = re.sub(r'[ \t()()]+’, ‘‘, cleaned_name)
# 3. 連続するアンダースコアを一つにまとめる
cleaned_name = re.sub(r’
{2,}’, ‘‘, cleaned_name)
# 4. 先頭または末尾のアンダースコアを除去 (もしあれば)
cleaned_name = cleaned_name.strip(‘
‘)
return cleaned_name

既存の列名リストに加工関数を適用して新しい列名リストを作成

new_columns_list = [clean_column_name(col) for col in df.columns]

新しい列名リストを .columns 属性に代入

df.columns = new_columns_list

print(“\n変更後のDataFrame (.columns 代入 + 加工):”)
print(df)
print(“\n変更後の列名:”, df.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame (.columns 代入 + 加工):
社員コード 氏名_フルネーム 所属部署 年齢 入社日
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘社員コード’, ‘氏名_フルネーム’, ‘所属部署’, ‘年齢’, ‘入社日’]
“`

.rename() メソッドに関数を渡す方法と結果は同じですが、こちらは元のDataFrameが直接変更される点が異なります。どちらの方法を使うかは、コードのスタイルや可読性、そして元のDataFrameを残しておきたいかどうかに依存します。一般的には、特定の列だけ変更したい場合は.rename()(辞書)、全ての列名をルールに基づいて一括変更したい場合は.rename()(関数)または.columns属性への代入(リスト内包表記など)が使われます。

.columns 属性への直接代入のまとめ

  • 用途: 全ての列名を新しいリストで置き換えたい場合。既存の列名リストを加工して一括変更したい場合。
  • 方法: df.columns = [新しい列名1, 新しい列名2, ...] のように、新しい列名のリストを.columns属性に代入する。
  • 戻り値: この操作自体はNoneを返します。DataFrameは直接変更されます。
  • 利点: 全ての列名を一度に置き換えるのが最もシンプル。データ読み込み後に列名をまとめて設定する場合などに便利。
  • 欠点: 元のDataFrameの列数と新しいリストの要素数が一致しないとエラーになる。部分的な列名変更には向かない(.rename()を使うべき)。

6. .set_axis() メソッドによる列名変更

.set_axis() メソッドは、DataFrameのインデックス(行ラベル)またはカラム(列ラベル)を新しいラベルのリストで置き換えるためのメソッドです。.columns 属性への直接代入と似ていますが、inplace オプションがある点で異なります。

6.1. axis=1 を指定して列名を変更する

.set_axis() は、axis 引数でどの軸のラベルを変更するかを指定します。axis=0 または 'index' を指定すると行インデックス、axis=1 または 'columns' を指定すると列名が変更されます。列名を変更したいので、axis=1 を指定します。

新しい列名のリストを第一引数に渡し、axis=1 を指定します。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())

新しい列名のリスト (元の列数と同じである必要がある)

new_column_names = [‘employee_id’, ‘full_name’, ‘department’, ‘age’, ‘hire_date’]

set_axis() メソッドを使って列名を変更 (axis=1 を指定)

new_df_setaxis = df.set_axis(new_column_names, axis=1) # デフォルトは inplace=False

print(“\n変更後のDataFrame (set_axis):”)
print(new_df_setaxis)
print(“\n変更後の列名:”, new_df_setaxis.columns.tolist())

元のDataFrameは変更されていないことを確認

print(“\n元のDataFrame列名:”, df.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame (set_axis):
employee_id full_name department age hire_date
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘employee_id’, ‘full_name’, ‘department’, ‘age’, ‘hire_date’]

元のDataFrame列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]
“`

結果は.columns属性への直接代入と似ていますが、デフォルトでは新しいDataFrameを返す点が.columns属性への代入とは異なります。

6.2. inplace=True オプション

.set_axis() メソッドも .rename() メソッドと同様に inplace=True オプションを持っています。これを指定すると、元のDataFrameが直接変更されます。

“`python
import pandas as pd

ダミーデータの作成 (再掲)

data = {
‘社員コード’: [101, 102, 103, 104, 105],
‘氏名(フルネーム)’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘所属部署 ‘: [‘営業部’, ‘開発部’, ‘営業部’, ‘広報部’, ‘開発部’],
‘年齢 ‘: [30, 25, 35, 28, 32],
‘入社日’: [‘2015-04-01’, ‘2018-10-01’, ‘2013-07-01’, ‘2017-01-15’, ‘2016-09-01’]
}
df = pd.DataFrame(data)

print(“変更前の列名:”, df.columns.tolist())

新しい列名のリスト (元の列数と同じである必要がある)

new_column_names = [‘employee_id’, ‘full_name’, ‘department’, ‘age’, ‘hire_date’]

set_axis() メソッドを inplace=True で実行

df.set_axis(new_column_names, axis=1, inplace=True) # inplace=True を指定

print(“\n変更後のDataFrame (set_axis with inplace=True):”)
print(df) # df 自体が変更されている
print(“\n変更後の列名:”, df.columns.tolist())
“`

実行結果:

“`
変更前の列名: [‘社員コード’, ‘氏名(フルネーム)’, ‘所属部署 ‘, ‘年齢 ‘, ‘入社日’]

変更後のDataFrame (set_axis with inplace=True):
employee_id full_name department age hire_date
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

変更後の列名: [‘employee_id’, ‘full_name’, ‘department’, ‘age’, ‘hire_date’]
“`

inplace=True を指定した場合は、.columns属性への直接代入と同じように元のDataFrameが変更されます。.set_axis(axis=1, inplace=True).columns = [...] とほぼ等価と考えられます。

.set_axis() メソッドのまとめ

  • 用途: .columns属性への直接代入と同様に、全ての列名を新しいリストで置き換えたい場合。inplace オプションを使いたい場合。
  • 方法: df.set_axis([新しい列名1, ...], axis=1, inplace=True/False) を使う。
  • 戻り値: デフォルトでは新しいDataFrameを返す。inplace=True の場合は None を返す。
  • 利点: .columns 属性への代入に inplace オプションを追加したようなもの。行インデックスと列名の両方に使える汎用メソッド。
  • 欠点: .columns 属性への代入と同様に、列数が一致しないとエラーになる。部分的な列名変更には向かない。.rename()ほど一般的ではないかもしれない(.columns 代入や .rename() で事足りることが多いため)。

7. 各手法の比較と使い分け

ここまで3つの主要な列名変更方法を見てきました。それぞれの特徴を理解した上で、状況に応じて最適な方法を選択することが重要です。

方法 用途 変更対象 戻り値 / 元のDataFrame 必要な情報 利点 欠点
.rename() (辞書) 特定の列名だけを変更 指定した列名 新しいDataFrame (デフォルト) {元の名: 新しい名}辞書 柔軟性が高い。一部の列だけ変更可能。元の列が存在しない場合もエラーにならない。 全ての列を変更する場合は辞書が長くなる。
.rename() (関数) ルールに基づいた一括変換 全ての列名 新しいDataFrame (デフォルト) 変換関数 複雑なルールで一括変更が可能。元の列が存在しない場合もエラーにならない。 関数の定義が必要(簡単な場合はラムダ関数)。
.columns = [...] 全ての列名を新しいリストで置換 全ての列名 元のDataFrameが直接変更 新しい列名のリスト シンプルで直感的。全ての列を置き換える場合に記述が短い。 列数が一致しないとエラー。部分的な変更は不可。元のDataFrameが必ず変更される。
.set_axis(axis=1) 全ての列名を新しいリストで置換 全ての列名 新しいDataFrame (デフォルト) 新しい列名のリスト .columns = [...]inplace オプションが付いたようなもの。 列数が一致しないとエラー。部分的な変更は不可。

使い分けの目安:

  • 「この列の名前だけを直したい」 -> .rename() (辞書) が最適です。最もシンプルで間違いが少ないでしょう。
  • 「全ての列名の前後の空白を削除したい」「スペースをアンダースコアにしたい」「全て小文字にしたい」など、決まったルールで全ての列名を変換したい -> .rename() (関数) または .columns = [加工したリスト] が適しています。.rename() は新しいDataFrameを返す(またはinplace=Trueで安全に制御できる)点で、.columns = [...] はシンプルな記述で元のDataFrameを変更する点で、それぞれ利点があります。どちらを選んでも良いですが、リスト内包表記に慣れていれば.columns = [...]も非常に簡潔に書けます。
  • 「データファイルを読み込んだがヘッダー行がないので、最初から全ての列名を自分で設定したい」 -> .columns = [...] が最も一般的で簡単です。
  • .columns = [...] と同じことをしたいが、inplace=True のように新しいDataFrameと元のDataFrameのどちらを残すかを選びたい」 -> .set_axis(axis=1) が使えます。ただし、.columns = [...] で新しいDataFrameに代入することも容易なので、.set_axis() は必須ではありません。

多くの場合、.rename() (辞書) か .columns = [...] (リスト or 加工リスト) で事足ります。まずはこの2つの方法をしっかりと使い分けられるようになるのがおすすめです。

8. 実践的なシナリオと応用

これまでに学んだ方法を、実際のデータ分析でよく遭遇するシナリオに適用してみましょう。

シナリオ1: データ読み込み時に列名を指定する

pd.read_csv()などの関数を使ってデータを読み込む際、同時に列名を指定することができます。これには names 引数を使用します。これは、.columns = [...] をデータ読み込みの段階で行うようなイメージです。

特に、ヘッダー行がないファイルや、ヘッダー行はあるがそれを使わずに自分で列名を付けたい場合に便利です。

“`python
import pandas as pd
import io # 文字列をファイルのように扱うためのモジュール

csv_data = “””
101,山田太郎,営業部,30,2015-04-01
102,佐藤花子,開発部,25,2018-10-01
103,田中一郎,営業部,35,2013-07-01
104,鈴木久美子,広報部,28,2017-01-15
105,高橋健太,開発部,32,2016-09-01
“””

io.StringIOを使って文字列をファイルのように扱う

header=None を指定してヘッダー行がないことを示す

names で新しい列名をリストで指定

df_read = pd.read_csv(io.StringIO(csv_data), header=None, names=[‘ID’, ‘Name’, ‘Department’, ‘Age’, ‘Hire_Date’])

print(“読み込み時に列名を指定したDataFrame:”)
print(df_read)
print(“\n列名:”, df_read.columns.tolist())
“`

実行結果:

“`
読み込み時に列名を指定したDataFrame:
ID Name Department Age Hire_Date
0 101 山田太郎 営業部 30 2015-04-01
1 102 佐藤花子 開発部 25 2018-10-01
2 103 田中一郎 営業部 35 2013-07-01
3 104 鈴木久美子 広報部 28 2017-01-15
4 105 高橋健太 開発部 32 2016-09-01

列名: [‘ID’, ‘Name’, ‘Department’, ‘Age’, ‘Hire_Date’]
“`

このように、ファイルを読み込む時点で列名を適切に設定することで、その後の列名変更の手間を省くことができます。header=Nonenames はセットで使うことが多いです。

シナリオ2: データ結合(マージ)前の列名正規化

複数のデータフレームを結合(マージ)する場合、結合キーとなる列の名前がデータフレーム間で一致している必要があります。また、結合後の列名が分かりやすくなるように、他の列名も正規化しておくと良いでしょう。

例えば、「従業員基本情報」と「部署情報」の2つのデータフレームがあり、それぞれ列名が異なるとします。

“`python
import pandas as pd

データフレーム1: 従業員基本情報

data_emp = {
‘employee_id’: [101, 102, 103, 104, 105],
‘employee_name’: [‘山田太郎’, ‘佐藤花子’, ‘田中一郎’, ‘鈴木久美子’, ‘高橋健太’],
‘dept_code’: [‘SALES’, ‘DEV’, ‘SALES’, ‘PR’, ‘DEV’] # 部署コードで管理
}
df_emp = pd.DataFrame(data_emp)

データフレーム2: 部署情報

data_dept = {
‘CODE’: [‘SALES’, ‘DEV’, ‘PR’, ‘ADMIN’], # こちらはCODEという列名
‘部署名 ‘: [‘営業部’, ‘開発部’, ‘広報部’, ‘管理部’] # 列名にスペース、日本語
}
df_dept = pd.DataFrame(data_dept)

print(“df_emp 列名:”, df_emp.columns.tolist())
print(“df_dept 列名:”, df_dept.columns.tolist())

結合したいが、df_dept の列名がマージに適さない

df_dept を変更する

‘CODE’ を ‘dept_code’ に変更 (結合キーに合わせる)

‘部署名 ‘ のスペースを削除し、英語名 ‘department_name’ に変更

df_dept の列名変更

df_dept_cleaned = df_dept.rename(columns={
‘CODE’: ‘dept_code’, # 結合キーに合わせて変更
‘部署名 ‘: ‘department_name’ # 日本語かつスペースありを英語に変更
})

print(“\ndf_dept 変更後の列名:”, df_dept_cleaned.columns.tolist())

変更後のデータフレームを使ってマージ

merged_df = pd.merge(df_emp, df_dept_cleaned, on=’dept_code’, how=’left’)

print(“\nマージ後のDataFrame:”)
print(merged_df)
“`

実行結果:

“`
df_emp 列名: [‘employee_id’, ‘employee_name’, ‘dept_code’]
df_dept 列名: [‘CODE’, ‘部署名 ‘]

df_dept 変更後の列名: [‘dept_code’, ‘department_name’]

マージ後のDataFrame:
employee_id employee_name dept_code department_name
0 101 山田太郎 SALES 営業部
1 102 佐藤花子 DEV 開発部
2 103 田中一郎 SALES 営業部
3 104 鈴木久美子 PR 広報部
4 105 高橋健太 DEV 開発部
“`

このように、データ結合を行う前には、キーとなる列名が一致しているかを確認し、必要に応じて.rename()などで変更することが重要です。また、結合後のデータフレームの列名も分かりやすくなるように、事前に他の列名も整理しておくと、その後の分析がスムーズになります。

シナリオ3: 不要な文字やスペース、日本語列名のクリーニング

これは特に日本の企業でExcelなどで作成されたデータを扱う際によく発生する問題です。列名に全角文字、スペース、括弧、ハイフンなどが含まれていると、.(ドット)記法でアクセスできなかったり、集計処理でエラーになったりすることがあります。

例えば、以下のDataFrameがあるとします。

“`python
import pandas as pd

data_dirty = {
‘商品 ID’: [1, 2, 3],
‘価格(税抜)’: [1000, 2500, 300],
‘在庫数-倉庫A’: [10, 5, 20],
‘備考 ‘: [‘なし’, ‘限定品’, ‘セール’] # 末尾にスペース
}
df_dirty = pd.DataFrame(data_dirty)

print(“変更前の列名:”, df_dirty.columns.tolist())

列名をクリーニングする方針:

– 全角/半角スペース、括弧、ハイフンをアンダースコア ‘_’ に置換

– 前後の空白を除去

– 全て小文字に変換 (必要に応じて)

リスト内包表記と strメソッドチェーン、または正規表現でクリーニング

str.replace() を使う方法 (シンプルだが複数文字の置換には複数回必要)

new_cols = [col.strip().replace(‘ ‘, ‘‘).replace(‘(’, ‘‘).replace(‘)’, ‘‘).replace(‘-‘, ‘‘).lower() for col in df_dirty.columns]

正規表現 re.sub() を使う方法 (より柔軟)

import re

def clean_col_name_robust(col_name):
cleaned_name = col_name.strip()
# スペース(全角/半角)、括弧、ハイフンをアンダースコアに置換
cleaned_name = re.sub(r'[ \t()()-]+’, ‘‘, cleaned_name)
# 連続するアンダースコアを一つにまとめる
cleaned_name = re.sub(r’
{2,}’, ‘‘, cleaned_name)
# 先頭・末尾のアンダースコアを除去
cleaned_name = cleaned_name.strip(‘
‘)
# 全て小文字に変換
cleaned_name = cleaned_name.lower()
return cleaned_name

new_cols = [clean_col_name_robust(col) for col in df_dirty.columns]

.columns 属性に代入して変更

df_dirty.columns = new_cols

print(“\n変更後のDataFrame:”)
print(df_dirty)
print(“\n変更後の列名:”, df_dirty.columns.tolist())

クリーニング後の列名ならドット記法でアクセスしやすい

print(“\n’価格_税抜’列のデータ:”)
print(df_dirty.価格_税抜) # 列名に特殊文字やスペースがなければドット記法でアクセス可能
“`

実行結果:

“`
変更前の列名: [‘商品 ID’, ‘価格(税抜)’, ‘在庫数-倉庫A’, ‘備考 ‘]

変更後のDataFrame:
商品_id 価格_税抜 在庫数_倉庫a 備考
0 1 1000 10 なし
1 2 2500 5 限定品
2 3 300 20 セール

変更後の列名: [‘商品_id’, ‘価格_税抜’, ‘在庫数_倉庫a’, ‘備考’]

‘価格_税抜’列のデータ:
0 1000
1 2500
2 300
Name: 価格_税抜, dtype: int64
“`

このように、リスト内包表記と文字列操作(str.strip(), str.replace(), re.sub()など)を組み合わせることで、複数の列名を一括でクリーニングすることができます。.rename()に関数を渡す方法でも同様のことができます。

9. よくある落とし穴とトラブルシューティング

列名変更は一見簡単な作業ですが、思わぬ落とし穴にはまることもあります。ここでは、初心者がよく遭遇する問題とその対処法を紹介します。

9.1. typo (タイポ) による列名変更失敗

.rename()メソッドで辞書を使う場合、または.columns属性に代入するリストを自分で手入力する場合、元の列名のスペルや大文字/小文字、全角/半角、末尾のスペースなどが間違っていると、意図通りに変更されません。

例えば、「所属部署 」(末尾にスペースあり)という列名を変更しようとして、誤って「所属部署」(スペースなし)を指定してしまう、といったケースです。

“`python
import pandas as pd

data = {‘所属部署 ‘: [‘営業’, ‘開発’]} # 末尾にスペースあり
df = pd.DataFrame(data)

print(“元の列名:”, df.columns.tolist())

間違った列名を指定して rename を実行 (末尾のスペースがない)

df_renamed_error = df.rename(columns={‘所属部署’: ‘新しい部署名’}) # ‘所属部署’ は存在しない列名

print(“\n変更後の列名 (typoあり):”, df_renamed_error.columns.tolist())
“`

実行結果:

“`
元の列名: [‘所属部署 ‘]

変更後の列名 (typoあり): [‘所属部署 ‘]
“`

.rename()メソッドは、指定したキー(元の列名)が存在しない場合、エラーを出さずにその項目を無視します。そのため、変更されたことに気づかず、後続の処理でエラーが発生して初めて typo に気づく、ということがよくあります。

対処法:

  • 列名を正確に確認する: 変更前に必ず print(df.columns.tolist()) などで現在の列名を正確に確認しましょう。コピペを使うのが最も安全です。
  • Jupyter Notebookなどの環境を使う: 対話的にコードを実行できる環境では、列名を入力する際にTabキーで補完が効くことがあります。また、df.columns を表示して、そこから列名をコピー&ペーストするのが確実です。
  • .rename()の辞書を使う: .columns = [...] よりも、特定の列だけを確実に変更できる.rename()の辞書形式の方が、意図しない変更を防ぎやすいです。

9.2. inplace=True の副作用

前述の通り、inplace=True を指定すると、元のDataFrameが直接変更されます。これはメモリ効率が良い反面、元のデータを失ってしまうリスクがあります。特に、複数のステップを経てデータ加工を行う場合、途中の段階のデータが必要になったり、何か問題が発生したときに元の状態に戻せなくなったりすることがあります。

“`python
import pandas as pd

data = {‘A’: [1, 2], ‘B’: [3, 4]}
df = pd.DataFrame(data)
df_original = df.copy() # 元のデータをコピーしておく

print(“元のdf:”, df)

df.rename(columns={‘A’: ‘X’}, inplace=True)
print(“\ninplace=Trueで変更後のdf:”, df)

この時点で、変数 df の内容は変更されてしまった

もし元のデータが必要になったら…

df_original は変更されていない

print(“\nコピーしておいたdf_original:”, df_original)

もしコピーしていなければ、元のデータに戻すのは難しい

“`

対処法:

  • 原則として inplace=True は使わない: new_df = df.method(...) のように、常に新しいDataFrameを生成するスタイルを推奨します。これにより、元のDataFrameは変更されずに保持されます。メモリが本当に逼迫しているような特殊なケースを除き、このスタイルの方が安全でコードの追跡も容易です。
  • コピーを作成する: どうしても元のDataFrameを変更したいが、後で戻す可能性がある場合は、df_copy = df.copy() のように明示的にDataFrameのコピーを作成しておきましょう。

9.3. 列数の不一致エラー (.columns 代入時)

.columns = [...] または .set_axis(axis=1) を使う場合、新しい列名のリストの要素数が元のDataFrameの列数と一致しないと ValueError が発生します。これは特に、自分で新しい列名リストを手入力した場合や、元のDataFrameの列数が変わるような操作(列の追加/削除)をした後に列名を変更しようとした場合に起こりやすいです。

“`python
import pandas as pd

data = {‘col1’: [1, 2], ‘col2’: [3, 4]}
df = pd.DataFrame(data)

print(“元の列名:”, df.columns.tolist()) # 2列
print(“元の列数:”, len(df.columns))

try:
# 意図的に列数を間違えた新しい列名リスト (3要素)
df.columns = [‘A’, ‘B’, ‘C’]
except ValueError as e:
print(f”\nエラーが発生しました: {e}”)
print(“新しい列名リストの要素数が、DataFrameの列数と一致しません。”)
“`

実行結果:

“`
元の列名: [‘col1’, ‘col2’]
元の列数: 2

エラーが発生しました: Length mismatch: Expected 2, got 3
新しい列名リストの要素数が、DataFrameの列数と一致しません。
“`

対処法:

  • 列数を常に確認する: 新しい列名のリストを作成する前に、必ず len(df.columns) で元のDataFrameの列数を確認しましょう。
  • 既存の列名リストを元に新しいリストを作成する: .columns = [加工関数(col) for col in df.columns] のように、元の df.columns をリスト内包表記などで加工して新しいリストを作成すれば、要素数が一致しないという問題は起こりません。
  • 特定の列だけ変更する場合は .rename() を使う: 全ての列名を置き換える必要がないなら、列数の制約がない.rename()メソッドを使いましょう。

9.4. 日本語などの非ASCII文字を含む列名

日本語の列名は Pandas 自体は問題なく扱えますが、一部のライブラリや、ファイルへの書き出し・読み込み時にエンコーディングの問題で文字化けしたり、エラーになったりすることがあります。また、コード上で入力する際に日本語変換の手間がかかります。前述の通り、ドット記法 (df.日本語列名) でアクセスすることもできません。

対処法:

  • ASCII文字のみの列名に統一する: 可能であれば、列名は英数字とアンダースコアなどを組み合わせたASCII文字のみで構成することをおすすめします。日本語の列名を読み込んだら、すぐに英語やローマ字の列名に変換する前処理を行いましょう。.rename() (辞書または関数) や .columns = [加工したリスト] の方法が使えます。
  • エンコーディングに注意する: 日本語を含むデータをファイルから読み書きする場合、適切なエンコーディング(例: ‘utf-8’, ‘shift_jis’)を指定する必要があります。

9.5. 元の列名を確認せずに変更しようとして失敗

これは 9.1 の typo にも関連しますが、「多分この列名だろう」と思い込んで列名を変更しようとした結果、失敗するケースです。特に、データソースのヘッダー行を直接見ずにコードを書き始めたり、ヘッダー行が複数行に分かれていたりする場合に起こりがちです。

対処法:

  • 最初のステップで必ず列名を確認する: データを読み込んだら、一番最初に print(df.columns.tolist()) を実行し、現在の正確な列名を確認する習慣をつけましょう。
  • データフレーム全体を表示して確認する: print(df.head()) などでデータフレームの先頭部分を表示し、列名とデータが一致しているか目視で確認することも有効です。

10. まとめ:あなたにとって最適な列名変更方法は?

この記事では、Pandas DataFrameの列名(カラム名)を変更するための主な3つの方法と、それぞれの詳細、コード例、使い分け、そしてよくある落とし穴について解説しました。

  1. .rename() メソッド:
    • 特定の列だけ変更したい → df.rename(columns={'元の名': '新しい名'})
    • ルールに基づいて一括変更したい → df.rename(columns=変換関数)
    • 元のDataFrameを残したい(新しいDataFrameを返す)場合に適しています。inplace=True もありますが、注意が必要です。
  2. .columns 属性への直接代入:
    • 全ての列名を新しいリストで置き換えたい → df.columns = ['新しい名1', '新しい名2', ...]
    • 元のDataFrameが直接変更されます。列数が一致しないとエラーになります。シンプルですが、全ての列を置き換える操作です。
  3. .set_axis(axis=1) メソッド:
    • .columns属性への代入に似ていますが、inplaceオプションが使えます。
    • df.set_axis(['新しい名1', ...], axis=1, inplace=True/False)
    • 全ての列を置き換える操作であり、列数が一致しないとエラーになります。

初心者の方がまず覚えるべきは、.rename() メソッドで辞書を使って特定の列名を変更する方法、そして .columns 属性にリストを代入して全ての列名を置き換える方法でしょう。ほとんどのケースはこの2つで対応できます。

データ分析の現場では、データの読み込み、列名クリーニング、欠損値処理、型変換、集計、可視化…といった様々な前処理が必要になります。列名変更はその中でも比較的早い段階で行われる重要なステップです。適切な列名に整えることで、その後の作業効率が格段に向上します。

この記事が、あなたのPandasを使ったデータ分析学習の一助となれば幸いです。列名変更のスキルをしっかりと身につけて、次のステップ(データ型の確認と変換、欠損値処理など)に進んでいきましょう!

もしこの記事を読んで「もっとこんなことを知りたい」「ここの部分がよく分からなかった」といった点があれば、ぜひフィードバックをいただけると嬉しいです。

Happy Data Analyzing!


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール