Pythonにおけるデータ分析ライブラリ「Pandas」を使いこなす上で、データの選択や抽出は避けて通れない非常に重要なステップです。
その中でも、ラベルに基づいてデータを操作するloc属性は、実務レベルのデータ処理において最も頻繁に利用されます。
locを正しく理解し活用することで、複雑なデータセットから特定の条件に合致する行を抽出したり、特定の列だけを効率的に加工したりすることが可能になります。
本記事では、locの基本的な概念から、スライスやリストを用いた高度な抽出、そして条件指定によるフィルタリングやデータの更新方法まで、実例を交えて詳しく解説します。
Pandasの操作効率を劇的に向上させるためのテクニックを、ぜひこの機会に習得してください。
Pandasのlocとは?基本概念とilocとの違い
PandasのDataFrameからデータを選択するためのメソッドには、主にlocとilocの2種類が存在します。
効率的なコーディングを行うためには、まずこの両者の違いを明確に理解しておく必要があります。
ラベル指定のlocと位置指定のiloc
loc属性の最大の特徴は「ラベル名」を指定してデータにアクセスすることにあります。
行ラベル (インデックス名) や列ラベル (カラム名) を直接指定するため、プログラムの可読性が高まり、データの構造が多少変わっても意図したデータを正確に取得できるという利点があります。
一方で、ilocは「行番号」や「列番号」といった整数値 (Integer-location) を使用してデータにアクセスします。
リストのインデックス操作と同じ感覚で使用できますが、列の並び順が変わると取得できるデータが変わってしまうリスクがあります。
locの基本的な書式
locを使用する際の基本的な構文は以下の通りです。
df.loc[行の指定, 列の指定]
行と列の指定には、単一のラベル、ラベルのリスト、あるいはスライス (範囲指定) を使用できます。
列の指定を省略した場合は、すべての列が対象となります。
事前準備:サンプルデータの作成
解説を進めるにあたり、まずは操作対象となるサンプル用のDataFrameを作成しましょう。
ここでは、従業員の情報を模したデータを使用します。
import pandas as pd
# サンプルデータの作成
data = {
'氏名': ['田中', '佐藤', '鈴木', '高橋', '伊藤'],
'年齢': [28, 35, 42, 25, 31],
'部署': ['営業', '総務', '開発', '営業', '開発'],
'給与': [300000, 350000, 500000, 280000, 450000]
}
# インデックスをIDとして設定
df = pd.DataFrame(data, index=['ID01', 'ID02', 'ID03', 'ID04', 'ID05'])
print(df)
氏名 年齢 部署 給与
ID01 田中 28 営業 300000
ID02 佐藤 35 総務 350000
ID03 鈴木 42 開発 500000
ID04 高橋 25 営業 280000
ID05 伊藤 31 開発 450000
このDataFrameを使用して、具体的な抽出方法を解説していきます。
基本的なデータの抽出方法
まずは、最もシンプルな単一要素や特定範囲の抽出方法から見ていきましょう。
単一の行・列を選択する
特定の行ラベルを指定すると、その行のデータがSeries形式で取得されます。
また、行ラベルと列ラベルを両方指定すれば、特定のセルの値をピンポイントで取得できます。
# 特定の行(ID02)を抽出
row_id02 = df.loc['ID02']
print("--- ID02のデータ ---")
print(row_id02)
# 特定の行と列を指定して値を取得
age_id03 = df.loc['ID03', '年齢']
print(f"\nID03の年齢: {age_id03}")
--- ID02のデータ ---
氏名 佐藤
年齢 35
部署 総務
給与 350000
Name: ID02, dtype: object
ID03の年齢: 42
複数の行や列をリストで指定する
複数のラベルを抽出したい場合は、ラベルをリスト形式 [] で渡します。
# 複数の行(ID01, ID03)を選択
multiple_rows = df.loc[['ID01', 'ID03']]
print("--- ID01とID03の行 ---")
print(multiple_rows)
# 複数の行と特定の列(氏名, 給与)を選択
subset = df.loc[['ID02', 'ID04'], ['氏名', '給与']]
print("\n--- 特定の行と列のサブセット ---")
print(subset)
--- ID01とID03の行 ---
氏名 年齢 部署 給与
ID01 田中 28 営業 300000
ID03 鈴木 42 開発 500000
--- 特定の行と列のサブセット ---
氏名 給与
ID02 佐藤 350000
ID04 高橋 280000
スライスによる範囲指定
Python標準のリストと同様に、スライス : を使用して範囲を指定できます。
ただし、locのスライスは終端のラベルも含まれるという点に注意が必要です。
# ID02からID04までの範囲を抽出(ID04も含まれる)
sliced_df = df.loc['ID02':'ID04', '氏名':'部署']
print(sliced_df)
氏名 年齢 部署
ID02 佐藤 35 総務
ID03 鈴木 42 開発
ID04 高橋 25 営業
通常のPythonのリスト操作では stop インデックスは含まれませんが、Pandasのlocではラベル名で指定するため、直感的に「ここからここまで」という指定が可能になっています。
条件指定(Boolean Indexing)による抽出
locの真価を発揮するのが、条件式を用いたデータのフィルタリングです。
これを「Boolean Indexing」と呼びます。
基本的な条件抽出
特定の列の値に基づいて行を絞り込むことができます。
例えば、年齢が30歳以上の従業員を抽出する場合は以下のように記述します。
# 年齢が30以上の行を抽出
over_30 = df.loc[df['年齢'] >= 30]
print(over_30)
氏名 年齢 部署 給与
ID02 佐藤 35 総務 350000
ID03 鈴木 42 開発 500000
ID05 伊藤 31 開発 450000
複数の条件を組み合わせる
複数の条件を指定する場合は、各条件を () で囲み、論理演算子を使用します。
| 演算子 | 意味 |
|---|---|
| & | AND(かつ) |
| | | OR(または) |
| ~ | NOT(ではない) |
# 部署が「開発」かつ 給与が480000より大きい行を抽出
condition = (df['部署'] == '開発') & (df['給与'] > 480000)
filtered_df = df.loc[condition]
print(filtered_df)
氏名 年齢 部署 給与
ID03 鈴木 42 開発 500000
抽出と同時に表示する列を制限する
条件に合致した行に対して、特定の列だけを表示したい場合、locの第2引数に列名を指定します。
# 給与が40万以上の人の「氏名」と「年齢」だけを取得
high_salary_info = df.loc[df['給与'] >= 400000, ['氏名', '年齢']]
print(high_salary_info)
氏名 年齢
ID03 鈴木 42
ID05 伊藤 31
データの更新と代入
locはデータの参照だけでなく、特定条件に合致するデータの上書き・更新にも利用されます。
条件に一致する要素の値を一括変更する
例えば、「営業」部署の全員の給与をアップさせる処理は、locを使えば一行で記述できます。
# 部署が営業の人の給与を 320000 に更新
df.loc[df['部署'] == '営業', '給与'] = 320000
print(df)
氏名 年齢 部署 給与
ID01 田中 28 営業 320000
ID02 佐藤 35 総務 350000
ID03 鈴木 42 開発 500000
ID04 高橋 25 営業 320000
ID05 伊藤 31 開発 450000
SettingWithCopyWarning を回避する
Pandasを操作していると SettingWithCopyWarning という警告に遭遇することがあります。
これは、データのコピーに対して値を代入しようとした際に発生します。
df[df[‘年齢’] > 30][‘給与’] = 0 のように、チェーン形式で選択と代入を同時に行おうとすると、この警告が出やすくなります。
locを使用して 「どの行のどの列を更新するか」を一括で指定することが、この警告を回避し、安全にデータを更新するためのベストプラクティスです。
lambda式を活用した動的な抽出
locの行指定には、関数(特に名前のない一時的な関数であるlambda式)を渡すことも可能です。
これにより、現在のDataFrameの状態に基づいた動的な抽出が可能になります。
# 年齢が平均以上の人を抽出
average_age_staff = df.loc[lambda d: d['年齢'] > d['年齢'].mean()]
print(average_age_staff)
氏名 年齢 部署 給与
ID02 佐藤 35 総務 350000
ID03 鈴木 42 開発 500000
メソッドチェーンの中でフィルタリングを行いたい場合に、lambda式を用いると非常に強力な武器になります。
よくあるミスと注意点
locを使用する際に陥りやすいポイントをまとめました。
インデックスの重複:
DataFrameのインデックス(行ラベル)に重複がある場合、locでそのラベルを指定すると複数の行が返されます。意図せず複数のデータが取得される可能性があるため、インデックスの一意性には注意しましょう。存在しないラベルの指定:
存在しない行ラベルや列ラベルをlocに渡すと、KeyErrorが発生します。事前にdf.indexやdf.columnsで存在を確認するか、例外処理を検討してください。スライスの仕様:
先述の通り、locのスライスは終端を含みます。これはilocとの大きな違いであるため、混同しないようにしましょう。
まとめ
本記事では、Pandasの loc を用いたデータの抽出と更新方法について解説しました。
重要なポイントを振り返ります。
- locはラベルベースでデータにアクセスするための属性である。
- 行だけでなく、第2引数を利用して列の絞り込みも同時に行える。
- スライス指定時、終端ラベルが含まれる点に注意する。
- 条件指定(Boolean Indexing)を組み合わせることで、柔軟なデータ抽出が可能。
- データの更新時には、安全性の観点からlocを使用するのが望ましい。
Pandasを用いたデータ分析の現場では、いかに素早く正確に目的のデータへアクセスできるかが作業効率を左右します。
今回紹介したテクニックを駆使して、ぜひ自身のプロジェクトや業務でのデータ処理を効率化させてみてください。
基本的な使い方に慣れてきたら、次は at や iat といった高速な単一要素アクセス用のメソッドや、マルチインデックス(階層型インデックス)に対するlocの適用など、さらに一歩進んだテクニックに挑戦してみるのも良いでしょう。
