『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

【pandas】インデクス属性

インデクス属性

Series や DataFrame には、要素を抽出するためのインデクス属性 (loc, iloc, at, iat) が備えられています。

loc, iloc

Series や DataFrame の要素の参照方法は、時としてユーザーを混乱させることがあります。たとえば、次のように偶数ラベルを付した Series オブジェクトを生成したとします。

# PANDAS_SERIES_LOC

# In[1]

import numpy as np
import pandas as pd

# Seriesオブジェクトを生成
data = pd.Series(["apple", "orange", "banana", "grape", "strawberry"],
                 index = {2, 4, 6, 8, 10})

data[2] によるアクセスはラベル 2 にマップされた要素 “apple” を取得します (ディクショナリでいえばキー 2 に対応する値 “apple” を取り出すことに対応します)。

# In[2]

print(data[2])
# apple

しかし、data[1] と記述すると、1 というキーは存在しないので KeyError を発生します。

# In[3]

print(data[1])
# KeyError: 1

そうすると、data[1:3] のようなスライス表記もエラーを返しそうですが、実際には予想に反して 2 番目と 3 番目の要素を抽出します。

# In[4]

print(data[1:3])
# 4    orange
# 6    banana
# dtype: object

スライス表記は一般的な Python や NumPy と同じく、各要素に連番 0, 1, 2, 3, … を割り当てる方式でアクセスするからです。このようなスタイル混合は様々なミスを引き起こす要因となるので、アクセスのスタイルを明確にするために、lociloc という属性が用意されています。
 
loc属性はラベルを介して要素にアクセスします:

# In[5]

# ラベルを使ってスライス
print(data.loc[2:5])

# 2     apple
# 4    orange
# dtype: object

iloc属性は従来の Python スタイルにしたがって要素にアクセスします:

# In[6]

# 従来のPython方式でスライス
print(data.iloc[2:5])

# 6         banana
# 8          grape
# 10    strawberry
# dtype: object

DataFrame における loc と iloc 属性の使い方も確認しておきましょう。
次のコードで東北地方の面積と人口の表を作成します (Wikipedia から抜粋した 2015年の国勢調査にもとづくデータです)。

# PANDAS_DATAFRAME_LOC

# In[1]

# 東北地方の県別面積一覧(平方キロメートル)
area = pd.Series({"岩手":15275,
                  "福島":13784,
                  "秋田":11638,
                  "青森":9646,
                  "山形":9323,
                  "宮城":7282})

# 東北地方の県別人口一覧(人)
pop = pd.Series({"岩手":1279594,
                 "福島":1914039,
                 "秋田":1023119,
                 "青森":1308265,
                 "山形":1123891,
                 "宮城":2333899})

# 列ラベルの割り当て
columns = {"面積":area, "人口":pop}

# DataFrameを作成
data = pd.DataFrame(columns)

print(data)
#        面積       人口
# 岩手  15275  1279594
# 福島  13784  1914039
# 秋田  11638  1023119
# 青森   9646  1308265
# 山形   9323  1123891
# 宮城   7282  2333899

DataFrame の loc属性は行ラベルと列ラベルを使ってデータにアクセスします。たとえば、秋田県の人口を参照したいときは次のように記述します。

# In[2]

# 秋田県の人口密度を取得
print(data.loc["秋田", "人口"])

# 1023119

山形県の面積を取得する場合は次のように記述します。

# In[3]

# 山形県の面積を取得
print(data.loc["山形", "面積"])

# 9323

スライスを使って複数項目を参照することもできます。

# In[4]

# 福島、秋田、青森の面積と人口を取得
print(data.loc["福島":"青森"])

#        面積       人口
# 福島  13784  1914039
# 秋田  11638  1023119
# 青森   9646  1308265

実行結果を見てわかるように、ラベルによるスライスは NumPy 配列のインデックスによるスライスとは異なり、指定ラベルに対応する要素をすべて返します。
 
コロン (:) を使って行や列を参照することもできます。
たとえば、面積一覧が欲しい場合は次のように記述します。

# In[5]

# 東北地方の面積一覧を取得
print(data.loc[:, "面積"])

# 岩手    15275
# 福島    13784
# 秋田    11638
# 青森     9646
# 山形     9323
# 宮城     7282
# Name: 面積, dtype: int64

DataFrame の iloc属性は行と列に割り振られた連番 (暗黙的インデクス) を使ってデータにアクセスします。つまり NumPy の二次元配列と同じアクセススタイルとなります。たとえば、秋田県の人口密度にアクセスする場合は以下のように記述します。

# In[6]

# 秋田県の人口密度を取得
print(data.iloc[2, 0])

# 11638

ある行や列を参照したい場合なども、NumPy のアクセス方式に準じます。たとえば、青森県の面積と人口密度にアクセスしたい場合は data.iloc[3, :] と記述します。

# In[7]

# 青森県の面積と人口密度を取得
print(data.iloc[3, :])

# 面積       9646
# 人口    1308265
# Name: 青森, dtype: int64

このとき、上のプログラムの実行結果にあるように、参照した行のラベルも Name として表示されます。

at, iat

atiat は1つの要素しか参照できないという点を除いて、それぞれ loc, iloc と同じはたらきをします。loc, iloc があれば事足りるので、at, iat を積極的に使用する利点は特にありませんが、一応以下に使用例を載せておきます。最初に四国の各県の面積と人口の表を作成しておきます。

# PANDAS_AT

# In[1]

# 四国の県別面積一覧(平方キロメートル)
area = pd.Series({"徳島":4147,
                  "香川":1877,
                  "愛媛":5676,
                  "高知":7104})

# 四国の県別人口一覧(人)
pop = pd.Series({"徳島":755733,
                 "香川":976263,
                 "愛媛":1385262,
                 "高知":728276})

# 列ラベルの割り当て
columns = {"面積":area, "人口":pop}

# DataFrameを作成
data = pd.DataFrame(columns)

print(data)
#       面積       人口
# 徳島  4147   755733
# 香川  1877   976263
# 愛媛  5676  1385262
# 高知  7104   728276

at を使って愛媛県の面積にアクセスしてみます。

# In[2]

# 愛媛県の面積を取得
print(data.at["愛媛", "面積"])

# 5676

iat は 0 から始まる連番ラベルでアクセスします。
たとえば、香川県の人口を参照する場合は次のように記述します。

# In[3]

# 香川県の人口を取得
print(data.iat[1, 1])

# 976263

 

コメント

  1. HNaito より:

    下記は誤植と思われますので、ご確認ください。
     
    SERIES_LOC In[1] プログラムで下記の2行を追加。
    import numpy as np
    import pandas as pd
     
    SERIES_LOC In[7] プログラムのコメントで、# 秋田県の → # 青森県の
    SERIES_LOC In[7] プロクラムの下の文で、コード PD_16_7 の → 上のプログラムの

  2. あとりえこばと より:

    【ChatGPT解説】loc と iloc
     
    A: おい、昨日のプロジェクトで Pandas の loc と iloc を使う必要があるんだけど、どうやって使うんだっけ?
     
    B: わかる、Pandas の loc と iloc について教えてやるよ。まずは loc から説明するけど、これは行と列のラベルを使ってデータにアクセスする方法だ。例えば、データフレーム df があったとして、df.loc[行ラベル, 列ラベル] のように使うんだ。

    A: なるほど、行と列のラベルで指定するんだね。じゃあ、具体的な例を教えてくれる?
     
    B: もちろん。例えば、df.loc[2, ‘列A’] は df の 2 行目の ‘列A’ にアクセスするよ。また、df.loc[:, ‘列B’] は全ての行の ‘列B’ にアクセスする。

    A: 分かった、ラベルを指定してデータにアクセスできるんだね。では次は iloc はどうなんだ?
     
    B: iloc は行と列のインデックスを使ってデータにアクセスする方法だ。具体的には、df.iloc[行インデックス, 列インデックス] のように使うよ。

    A: インデックスとは具体的にどういうこと?
     
    B: インデックスはデータの位置を表す番号のことだよ。データフレームの最初の行や列は 0 から始まる番号が割り当てられる。例えば、df.iloc[2, 0] は df の 3 行目と 1 列目にアクセスする。

    A: なるほど、インデックスを使って位置を指定するんだね。それで、行と列をまとめて指定することもできるのか?
     
    B: そうだよ。例えば、df.iloc[1:3, 2:4] は df の 2 行目から 3 行目までの行と、3 列目から 4 列目までの列にアクセスする。
     
    A: よく分かったよ、ありがとう!loc と iloc の違いも理解できたし、プロジェクトで使うのに問題なさそうだ。