とあるメーカーエンジニアの趣味備忘録

Python, マイコンいじり, 日々の呟きなど

PandasのDataFrameに対してiterrows()メソッドで一つずつ要素を呼び出して,ラベルが存在するかどうかを確かめようとしてエラーに引っかかった話

題名を読んで,わかっている人からすると「何を当たり前のことを書いているんだ」と言われてしまいそうだが,自分がこれで結構引っかかったので一応メモ.

先ず,pandas の DataFrame 配列において

あるラベル名のカラムが存在するのかどうかを確かめたいという時がある.

そんな時には,DataFrame配列の有しているcolumnsという変数を参照することによってその確認を行うことができる.

まず,次の DataFrame配列を用意する.

import pandas as pd
test = [
    ["Taro", "Tokyo"],
    ["Jiro", "Osaka"],
    ["Sinya", "Aichi"],
    ["Haruki", "Hokkaido"]
]
index = ["user", "address"]
# DataFrame
testpd = pd.DataFrame(test, columns = index)
testpd

f:id:makutsueeken5:20190218151354j:plain

そして,columnsという変数を参照して,特定のラベル名のカラムが存在するかどうかを確かめることができる.

if "address" in testpd.columns:
    print(True)
else:
    print(False)

出力結果

True

また,DataFrame配列の中身を一つ一つ取り出したくなる時がある.

そんな時には,DataFrame配列の有するメソッドであるiterrows()を用いることによって実現することができる.

ここからが本題であるが,iterrows()を用いて一つ一つ取り出したアイテムに対して,columnsという変数を参照して,特定のラベル名のカラムが存在するかどうかを確かめようとすると,

for index, item in testpd.iterrows():
    # index は 'int' type
    # item は 'pandas.Series' type
    print("************************************")
    print(item)
    # 'pandas.Series' type に対して,DataFrame型の時と同様に ".columns" を呼び出してみる
    if "address" in item.columns:
        print(True)
    else:
        print(False)

出力結果

True
************************************
user        Taro
address    Tokyo
Name: 0, dtype: object
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-27-555c8ebbccf2> in <module>()
      8     # 'pandas.Series' type に対して,DataFrame型の時と同様に ".columns" を呼び出してみる
      9     try:
---> 10         if "address" in item.columns:
     11             print(True)
     12         else:

~\Anaconda3\lib\site-packages\pandas\core\generic.py in __getattr__(self, name)
   4366         if (name in self._internal_names_set or name in self._metadata or
   4367                 name in self._accessors):
-> 4368             return object.__getattribute__(self, name)
   4369         else:
   4370             if self._info_axis._can_hold_identifiers_and_holds_name(name):

AttributeError: 'Series' object has no attribute 'columns'

このようにAttributeErrorを食らってしまう.

というのも,公式リファレンスを参照したところ

pandas.DataFrame.iterrows — pandas 0.24.1 documentation

iterrows()メソッドによって渡される値は'DataFrame'オブジェクトではなく,'Series'オブジェクトとして渡されるためである.

Seriesオブジェクトは,columnの無いDataFrameオブジェクト・一次元のDataFrameオブジェクトのようなものであるため,columnsを参照することができないのである.

その代わりに,Seriesオブジェクトはその行(index)のラベルを.keys()メソッドによって参照することができるのである.

for index, item in testpd.iterrows():
    # index は 'int' type
    # item は 'pandas.Series' type
    print("************************************")
    print(item)
    # 'pandas.Series' type に対して メソッド ".keys()" を呼び出してみる
    if "address" in item.keys():
        print(True)
    else:
        print(False)

出力結果

************************************
user        Taro
address    Tokyo
Name: 0, dtype: object
True
************************************
user        Jiro
address    Osaka
Name: 1, dtype: object
True
************************************
user       Sinya
address    Aichi
Name: 2, dtype: object
True
************************************
user         Haruki
address    Hokkaido
Name: 3, dtype: object
True

このようにして,indexを参照することができた.