Pandasを用いたデータ分析において、データの抽出は最も頻繁に行われる操作の一つです。
その中でも、行や列の番号を指定してデータを抽出するilocプロパティは、データの構造を正確に把握し、効率的な処理を行うために欠かせないツールです。
特にデータクレンジングや機械学習のプリプロセッシング(前処理)においては、特定の範囲を数値ベースで切り出す操作が多用されます。
本記事では、2026年現在の最新のPandas環境を前提に、ilocの基本的な使い方から応用、そしてパフォーマンスに直結するCopy-on-Write(CoW)への対応まで、実務で役立つ知識を詳しく解説します。
Pandasにおけるデータ抽出の基本
PandasのDataFrameからデータを抽出する方法はいくつかありますが、大きく分けると「ラベル(名前)」で指定する方法と「位置(整数)」で指定する方法の2種類が存在します。
ilocは後者の「位置」に基づいた抽出を担うインターフェースです。
ilocの名前は integer-location に由来しており、その名の通り「0から始まる整数値」を用いて行と列を指定します。
これは、Pythonの標準的なリスト(list)やNumPy配列のインデックス指定と同じ感覚で利用できるため、プログラミング経験者にとっては馴染みやすい仕様となっています。
一方、ラベルベースで指定するlocとの違いを明確に理解しておくことが、バグの少ないコードを書くための第一歩です。
インデックス(行名)が数値であっても、それが「ラベルとしての数値」なのか「位置としての数値」なのかによって、locとilocの結果は異なります。
最新のPandas 3.0系以降では、この区別がより厳格かつ効率的に処理されるよう最適化されています。
ilocの基本的な使い方
まずは、最もシンプルな単一要素の抽出や行・列の指定方法を見ていきましょう。
基本的な構文は df.iloc[行のインデックス, 列のインデックス] という形を取ります。
単一の行・列・要素の抽出
特定の1行だけを取得したい場合や、特定のセルの値を取得したい場合に利用します。
import pandas as pd
# サンプルデータの作成
data = {
'Name': ['Alice', 'Bob', 'Charlie', 'David'],
'Age': [25, 30, 35, 40],
'City': ['Tokyo', 'Osaka', 'Nagoya', 'Fukuoka']
}
df = pd.DataFrame(data)
# 0番目の行(1行目)を抽出
first_row = df.iloc[0]
# 2番目の行、1番目の列(3行目のAge)を抽出
specific_value = df.iloc[2, 1]
print("--- 1行目の抽出 ---")
print(first_row)
print("\n--- 3行目のAgeの値 ---")
print(specific_value)
--- 1行目の抽出 ---
Name Alice
Age 25
City Tokyo
Name: 0, dtype: object
--- 3行目のAgeの値 ---
35
行のみを指定した場合、戻り値は Series オブジェクトになります。
また、行と列の両方に単一の整数を指定すると、そのセルの値が直接返されます。
複数の要素をリストで指定する
特定の連続していない行や列を抽出したい場合は、整数のリストを渡すことができます。
# 0番目と2番目の行を抽出
subset_rows = df.iloc[[0, 2]]
# すべての行に対して、0番目と2番目の列(NameとCity)を抽出
subset_cols = df.iloc[:, [0, 2]]
print("--- 0番目と2番目の行 ---")
print(subset_rows)
print("\n--- NameとCity列のみ ---")
print(subset_cols)
--- 0番目と2番目の行 ---
Name Age City
0 Alice 25 Tokyo
2 Charlie 35 Nagoya
--- Name列とCity列 ---
Name City
0 Alice Tokyo
1 Bob Osaka
2 Charlie Nagoya
3 David Fukuoka
ここで使用した : (コロン)は、すべての要素を選択することを意味します。
df.iloc[:, [0, 2]] と書くことで、「すべての行を対象に、0番目と2番目の列を取り出す」という指定が可能です。
スライスによる範囲指定
Pythonのリストと同様に、ilocではスライスを用いた範囲指定が可能です。
スライスの構文は start:stop ですが、注意点として stopで指定したインデックスの1つ手前まで が抽出対象となる点が挙げられます。
行と列をスライスで切り出す
大量のデータから一部のブロックを抜き出す際に非常に便利です。
# 1行目から2行目まで(インデックス1から3の手前まで)を抽出
# 1列目から2列目まで(インデックス1から3の手前まで)を抽出
sliced_df = df.iloc[1:3, 1:3]
print("--- スライスによる抽出結果 ---")
print(sliced_df)
--- スライスによる抽出結果 ---
Age City
1 30 Osaka
2 35 Nagoya
負のインデックスによる末尾からの指定
末尾から数えてデータを抽出することも可能です。
例えば「最後の3行だけを取得したい」といった場合に有効です。
# 最後の2行を抽出
last_two_rows = df.iloc[-2:]
# 最後の列以外のすべてを抽出
all_except_last_col = df.iloc[:, :-1]
print("--- 最後の2行 ---")
print(last_two_rows)
print("\n--- 最後の列を除外 ---")
print(all_except_last_col)
--- 最後の2行 ---
Name Age City
2 Charlie 35 Nagoya
3 David 40 Fukuoka
--- 最後の列を除外 ---
Name Age
0 Alice 25
1 Bob 30
2 Charlie 35
3 David 40
負のインデックスを活用することで、データの総件数が不明な場合でも柔軟に末尾のデータを操作できます。
locとilocの決定的な違い
初心者から中級者までが最も混同しやすいのが loc と iloc の違いです。
2026年の最新バージョンにおいても、この使い分けはパフォーマンスと正確性の観点から非常に重要視されています。
以下の表に、主要な違いをまとめました。
| 特徴 | loc | iloc |
|---|---|---|
| 指定方法 | ラベル(インデックス名、列名) | 位置(0からの整数) |
| スライスの終点 | 指定した終点を含める(Inclusive) | 指定した終点を含めない(Exclusive) |
| 主な用途 | 条件指定(Boolearn)や名前ベースの操作 | 特定の行・列番号による固定的な操作 |
特にスライスの挙動の違いは、オフバイワン・エラー(1つズレるエラー)の原因になりやすいため、注意が必要です。
loc['A':'C'] はCを含みますが、iloc[0:2] はインデックス2(3つ目の要素)を含みません。
最新のCopy-on-Write (CoW) とilocの関係
Pandas 3.0以降、デフォルトで有効化されているのが Copy-on-Write (CoW) という仕組みです。
これは、iloc や loc でデータを抽出した際の挙動に大きな変化をもたらしました。
従来の挙動とCoW導入後の違い
これまでのPandasでは、スライスによって抽出されたオブジェクト(ビュー)に対して値を変更すると、元のDataFrameも同時に書き換わってしまうことがありました。
また、これが原因で SettingWithCopyWarning という警告が頻発していました。
CoWが導入された2026年現在の環境では、「抽出したデータに変更を加えない限り、メモリ上の実体は共有されるが、変更を加えた瞬間に新しいコピーが作成される」 という動作が基本となります。
# Copy-on-Writeの影響を確認する例(Pandas 3.0+)
df_original = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# ilocで一部を抽出
subset = df_original.iloc[0:2, 0:2]
# subsetの値を変更する
subset.iloc[0, 0] = 100
print("--- subsetの結果(変更済み) ---")
print(subset)
print("\n--- 元のdf_originalの結果(変更されない) ---")
print(df_original)
実行結果(CoW有効時):
--- subsetの結果(変更済み) ---
A B
0 100 4
1 2 5
--- 元のdf_originalの結果(変更されない) ---
A B
0 1 4
1 2 5
2 3 6
CoWの導入により、不意に元のデータが書き換わってしまうバグが劇的に減少しました。 また、必要になるまでコピーを作成しないため、メモリ効率も向上しています。
iloc を使ってサブセットを作成し、それをクリーニングするようなワークフローがより安全に行えるようになっています。
パフォーマンスを最適化するためのヒント
データ量が増大する現代の分析シーンにおいて、iloc の使い方も最適化が必要です。
1. 単一要素へのアクセスは at / iat を検討する
もし「特定の1マス」の値を高速に取得・更新したいだけであれば、iloc よりも iat を使用する方が高速です。
iloc はスライスや複数行指定など多機能である分、オーバーヘッドが存在します。
# 高速な単一要素アクセス
value = df.iat[0, 1]
2. 連続した行のアクセスにはスライスを使う
リスト形式 df.iloc[[0, 1, 2]] で指定するよりも、スライス形式 df.iloc[0:3] を使う方が内部処理が簡略化され、速度面で有利です。
3. Chained Indexing(連鎖インデックス)を避ける
df.iloc[0][1] = 10 のような書き方は、一時的なオブジェクトを作成するためパフォーマンスを低下させるだけでなく、CoWの恩恵を十分に受けられない可能性があります。
常に df.iloc[0, 1] = 10 と1つの括弧内で指定することを心がけましょう。
ilocの応用:条件抽出と組み合わせる
iloc 自体は整数インデックスしか受け付けませんが、numpy.where や論理インデックスと組み合わせることで、「条件に合致したデータの位置を特定し、その位置を使って抽出する」といった高度な操作が可能です。
import numpy as np
# Ageが30以上のデータのインデックス(位置)を取得
indices = np.where(df['Age'] >= 30)[0]
# その位置を使ってilocで抽出
result = df.iloc[indices]
print("--- Ageが30以上の行を位置ベースで抽出 ---")
print(result)
このように、名前ではなく「データの順番」や「特定条件の物理的な位置」が重要になるシーンでは、iloc が強力な武器になります。
まとめ
Pandasの iloc は、データの位置を正確に制御するための非常に強力なインターフェースです。
2026年現在のPandasにおいては、単なるデータの取り出し手段にとどまらず、Copy-on-Writeによる安全なメモリ管理に基づいた設計がなされています。
本記事で解説した以下のポイントを意識することで、より堅牢なデータ分析コードを書くことができるでしょう。
- ilocは0から始まる整数ベースでの指定であること
- スライス指定では終点を含まないという特性を理解すること
- Copy-on-Writeにより、抽出後の変更が元データに影響しなくなった(安全になった)こと
- パフォーマンス向上のために at/iat と使い分けること
特に大規模なデータセットを扱う場合や、パイプラインの一部としてコードを組み込む場合は、これらの仕様変更や最適化の恩恵を最大限に活用してください。
インデックス操作をマスターすることは、Pandasを使いこなす上での最大の壁であり、同時に最大の武器となります。
