Pythonを用いたデータ分析において、データフレームから特定の列を抽出する操作は、最も頻繁に行われる基本的な工程の一つです。
分析対象となるデータセットは、時に数百以上のカラムを持つことがあり、必要な情報だけを効率よく取り出すスキルは、コードの可読性や処理速度を向上させるために不可欠です。
本記事では、Pandasにおける列抽出の基本から、特定の条件に基づいた高度な抽出手法まで、実務で役立つ具体的なテクニックを網羅的に解説します。
1. 基本的な列抽出の方法
Pandasでデータフレームの列を選択する最もシンプルな方法は、[](ブラケット)を使用する方法です。
抽出したい列が1つの場合と複数の場合で、戻り値の型が異なる点に注意が必要です。
1.1 単一列の抽出(SeriesとDataFrame)
1つの列を抽出する場合、列名を文字列として指定します。
import pandas as pd
# サンプルデータの作成
data = {
'ID': [1, 2, 3],
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'City': ['Tokyo', 'Osaka', 'Nagoya']
}
df = pd.DataFrame(data)
# 単一列をSeriesとして抽出
name_series = df['Name']
print(name_series)
print(type(name_series))
0 Alice
1 Bob
2 Charlie
Name: Name, dtype: object
<class 'pandas.core.series.Series'>
ここで、列名をリスト形式(二重のブラケット)で渡すと、1列であってもDataFrameとして抽出されます。
# 単一列をDataFrameとして抽出
name_df = df[['Name']]
print(name_df)
print(type(name_df))
Name
0 Alice
1 Bob
2 Charlie
<class 'pandas.core.frame.DataFrame'>
1.2 複数列の抽出
複数の列を同時に抽出したい場合は、列名のリストをブラケット内に記述します。
この操作により、元のデータから必要なカラムだけを切り出した新しいデータフレームを作成できます。
# 複数列を抽出
sub_df = df[['ID', 'Age', 'City']]
print(sub_df)
ID Age City
0 1 25 Tokyo
1 2 30 Osaka
2 3 35 Nagoya
この際、リスト内に存在しない列名を指定するとKeyErrorが発生するため、動的に列を抽出する場合は事前に列名の存在チェックを行うことが推奨されます。
2. locプロパティによるラベルベースの抽出
locを使用すると、行と列をラベル(名前)で指定して抽出できます。
データフレームの操作において最も推奨される方法の一つです。
2.1 基本的な使い方
df.loc[行の指定, 列の指定]という形式で記述します。
すべての行を対象にする場合は、行の指定部分に:(コロン)を使用します。
# 全行の'Name'と'City'を抽出
selected_data = df.loc[:, ['Name', 'City']]
print(selected_data)
2.2 ラベルによるスライス
locの強力な機能の一つに、列名の範囲指定(スライス)があります。
これにより、開始列から終了列までを連続的に取得することが可能です。
# 'Name'から'City'までのすべての列を抽出
sliced_df = df.loc[:, 'Name':'City']
print(sliced_df)
Name Age City
0 Alice 25 Tokyo
1 Bob 30 Osaka
2 Charlie 35 Nagoya
注意点として、locによるスライスは終点の列(この例では’City’)も含まれるという性質があります。
Python標準のリストのスライスとは挙動が異なるため、混同しないようにしましょう。
3. ilocプロパティによる位置ベースの抽出
列名ではなく、列のインデックス(番号)で指定したい場合はilocを使用します。
3.1 インデックスによる指定
列番号は0から始まります。
特定の列番号をリストで指定したり、スライスを使用したりできます。
# 0番目と2番目の列を抽出
iloc_selected = df.iloc[:, [0, 2]]
print(iloc_selected)
3.2 数値によるスライス
ilocでのスライスは、通常のPythonリストと同様に「始点は含み、終点は含まない」というルールに従います。
# 1番目から2番目(3番目の手前まで)の列を抽出
iloc_sliced = df.iloc[:, 1:3]
print(iloc_sliced)
Name Age
0 Alice 25
1 Bob 30
2 Charlie 35
動的なループ処理や、列名が未確定で位置だけが決まっているデータ(ログデータなど)を扱う際に非常に重宝します。
4. 条件やパターンによる効率的な列抽出
大規模なデータセットでは、手動で列名をリストアップするのが困難な場合があります。
Pandasには、特定のパターンや条件に合致する列を抽出するための便利なメソッドが用意されています。
4.1 filterメソッドによる文字列検索
filterメソッドを使用すると、列名に特定の文字列が含まれているか、あるいは正規表現に一致するかで列を選択できます。
# サンプルデータの拡張
data_ext = {
'user_id': [1, 2],
'user_name': ['A', 'B'],
'test_score': [80, 90],
'test_date': ['2026-01-01', '2026-01-02'],
'memo': ['none', 'none']
}
df_ext = pd.DataFrame(data_ext)
# 列名に 'user' を含む列を抽出
user_cols = df_ext.filter(like='user')
print(user_cols)
user_id user_name
0 1 A
1 2 B
また、正規表現を用いる場合はregex引数を使用します。
# 'score' または 'date' で終わる列を抽出
regex_cols = df_ext.filter(regex='(score|date)$')
print(regex_cols)
4.2 select_dtypesによる型指定の抽出
数値データのみを計算対象にしたい、あるいはカテゴリカルデータのみをエンコーディングしたいといった場面では、select_dtypesが非常に便利です。
# 数値型(整数・浮動小数点数)の列のみを抽出
numeric_df = df_ext.select_dtypes(include=['number'])
# 文字列型(object型)の列のみを抽出
object_df = df_ext.select_dtypes(include=['object'])
print("--- Numeric Columns ---")
print(numeric_df.columns)
print("--- Object Columns ---")
print(object_df.columns)
--- Numeric Columns ---
Index(['user_id', 'test_score'], dtype='object')
--- Object Columns ---
Index(['user_name', 'test_date', 'memo'], dtype='object')
「特定の型を除外する」という操作も、exclude引数を用いることで簡単に実現できます。
5. 動的な列抽出の応用テクニック
実務のデータクレンジングでは、データフレームの内容に基づいて抽出する列を動的に決定することがあります。
5.1 リスト内包表記との組み合わせ
特定の条件を満たす列名の一覧をリスト内包表記で作成し、それをデータフレームに渡す手法は非常に柔軟性が高いです。
# 平均値が50以上の数値列のみを抽出する例
# (サンプルデータに平均が計算できる列が必要)
df_sample = pd.DataFrame({
'A': [10, 20, 30], # 平均20
'B': [60, 70, 80], # 平均70
'C': [100, 110, 120] # 平均110
})
# 各列の平均を計算し、50を超える列名を取得
target_cols = [col for col in df_sample.columns if df_sample[col].mean() > 50]
print(df_sample[target_cols])
5.2 欠損値(NaN)の割合によるフィルタリング
データ分析の前処理として、欠損値が多すぎる列を除外するという操作も列抽出の一種です。
# 欠損値を含むデータの作成
df_nan = pd.DataFrame({
'A': [1, 2, None],
'B': [None, None, None],
'C': [1, 2, 3]
})
# 欠損値が50%未満の列のみを保持
threshold = 0.5
limit = len(df_nan) * threshold
df_filtered = df_nan.dropna(axis=1, thresh=limit)
print(df_filtered)
dropna(axis=1)を使用することで、条件を満たさない「列」をまとめて削除(=必要な列だけを抽出)することができます。
6. 列抽出時のパフォーマンスとベストプラクティス
大量のデータを扱う際、抽出方法の選択が処理時間に影響を与えることがあります。
6.1 View(参照)とCopy(複製)の違い
Pandasで列を抽出した際、それが元のデータの「ビュー(参照)」なのか「コピー(複製)」なのかを意識することは重要です。
# 抽出したデータに対して値を変更しようとすると警告が出る場合がある
subset = df[['Name']]
# subset.loc[0, 'Name'] = 'New Name' # SettingWithCopyWarning のリスク
SettingWithCopyWarningを避けるためには、抽出した後にそのデータを独立して加工する場合、明示的に.copy()を呼び出すべきです。
# 安全な抽出とコピー
safe_subset = df[['Name', 'Age']].copy()
6.2 大規模データでの注意点
列の抽出自体はPandasにおいて非常に高速な部類に入りますが、locやilocをループの中で繰り返し呼び出すような処理は避けるべきです。
可能な限り「一度に必要な列をまとめて抽出する」、あるいは「ベクトル化された操作を行う」ことを心がけましょう。
また、メモリ節約の観点からは、読み込み段階(pd.read_csvなど)でusecols引数を使用して、必要な列だけをメモリに載せる手法も有効です。
# CSV読み込み時に列を絞り込む
# df = pd.read_csv('large_data.csv', usecols=['ID', 'Target'])
7. まとめ
Pandasにおける列の抽出は、単に特定の項目を取り出すだけでなく、データの構造を整理し、後続の分析プロセスをスムーズにするための重要なステップです。
- 基本的な抽出には
[]やリスト形式を使用する。 - ラベルによる厳密な指定や範囲指定には
locを活用する。 - 位置番号による指定には
ilocを利用する。 - 複雑なパターンやデータ型に基づく抽出には
filterやselect_dtypesが威力を発揮する。 - 抽出後の加工を想定する場合は
.copy()で安全性を確保する。
これらの手法を状況に応じて使い分けることで、効率的でミスの少ないデータ分析パイプラインを構築できるようになります。
特に、大規模なデータセットを扱うプロジェクトでは、初期段階でいかにスマートに必要な列を絞り込めるかが、作業全体のパフォーマンスを左右します。
本記事で紹介したテクニックを参考に、日々のコーディングに役立ててください。
