ここではPythonライブラリの中でもっとも頻繁に利用されるPanadasを徹底的に使いこなすためのシリーズ第2回目として、
PandasのDataFrameからデータを選択して取得する方法について解説します。
ここでは主に、dataframe[]、loc[]、iloc[]、 at[]、 iat[]、 iterrows()、items()の使い方について説明します。
なお、DataFrameからデータを絞り込む方法については別記事にて取り上げます。
DataFrame[]は、PandasのDataFrameからすべてのデータを選択して取得するときに便利です。
loc[]/iloc[]は、DataFrameから特定の行/列を選択してデータを取得(スライス)するときに利用します。
at[]/iat[]は、DataFrameから特定の値を取得するときに使います。
iterrows()は、DataFrameから1件ずつレコード(行)を取り込んで処理するときに便利です。
items()は、DataFrameから1件ずつSeries(特定の列の全行)を取り込んで処理するときに便利です。
この記事では、Pandasのライブラリを使用しますので
「記事(Article001) | 記事(Article002) | 記事(Article003) | 記事(Article004)」
を参照して事前にインストールしておいてください。
Pythonのコードを入力するときにMicrosoftのVisula Studio Codeを使用します。
まだ、インストールしていないときは「記事(Article001)」を参照してインストールしておいてください。
説明文の左側に図の画像が表示されていますが縮小されています。
画像を拡大するにはマウスを画像上に移動してクリックします。
画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。
画像の任意の場所をクリックして閉じることもできます。
-
まずはPandasのDataFrameにデータをロードする
行2-4ではPythonのライブラリを取り込んでいます。
行7-12ではPandasのDataFrameにロードするデータをdict型で定義しています。
行15ではPandasのDataFrame()メソッドでDataFrameにデータをロードしています。
行16ではPandasのto_datetime()メソッドでstr型の日時をdatetime型に変換しています。
行17ではDataFrameの内容を表示しています。
# Import the necessary libraries
import pandas as pd
import datetime as dt
import numpy as np
# Create DataFrame from list of lists
data = {
'category_name': ['JavaScript','jQuery','Python','C++','C#'],
'page_view': [100,150,900,600,700],
'exclude_me': [False, True, False, False, False],
'date_added': ['2021-01-05 11:29:59','2021-02-25 12:13:15','2021-05-25 05:06:59','2020-11-09 03:05:02','2019-12-05 01:02:03']
}
print(type(data))
# Load the data into dataframe
df = pd.DataFrame(data)
df['date_added'] = pd.to_datetime(df['date_added'], format='%Y-%m-%d %H:%M:%S') # Convert string to datetime format
print(df)
図1は実行結果です。
DataFrameの列名と列の値がレコード(行)単位に表示されています。
レコード(行)の先頭に表示されている数字(0-4)はレコード(行)のindex番号です。
index番号はPandasがデータをロードしたときに自動的に作成します。
このindex番号は後述するiloc[]、iat[]などで使用します。
-
DataFrameの列名、データ型、レコード(行)件数、列件数を取得する
行2ではDataFrameのinfo()メソッド(正式には属性と呼ぶ)でDataFrameの列名、データ型などを取得して表示しています。
行3ではDataFrameのshapeプロパティ(正式には属性と呼ぶ)からDataFrameのレコード(行)件数と列件数を取得しています。
変数「df_rows」にレコード(行)件数、変数「df_cols」には列件数が格納されます。
shapeで取得した情報はiloc[]、iat[]などで利用すると便利です。
# Print datafarme info (dtype, rows, cols)
print(df.info())
df_rows, df_cols = df.shape
print(f'rows={df_rows}, cols={df_cols}')
図2は実行結果です。
DataFrameの列名、列のデータ型などが表示されています。
また、レコード(行)件数と列件数も表示されています。
-
DataFrameの先頭と最終レコード(行)を取得する
行3ではDataFrameのhead()メソッドでDataFrameの先頭レコード(行)を取得して表示しています。
head()の引数にはレコード件数を指定します。
行4ではDataFrameのtail()メソッドで最終レコード(行)を取得して表示しています。
tail()の引数にはレコード件数を指定します。
# Print DataFrame df, df.head(1), df.tail(1)
print(df)
print(df.head(1))
print(df.tail(1))
図3は実行結果です。
DataFrameの先頭レコード(行)と最終レコード(行)が表示されています。
-
DataFrameの列名を選択してデータを取得する
行2-3ではDataFrameの列「category_name」を指定してDataFrameのSeriesを取得して表示しています。
行5-6ではDataFrameの複数の列「category_name, page_view」を指定してDataFrameのSeriesを取得して表示しています。
このようにDataFrameの「[]」では任意の列を指定してDataFrameのSeriesを選択することができます。
ちなみに「DataFrame[[col_name]]」のように二重の[[]]で囲むとDataFrameのSeriesではなく「DataFrame」を返します。
「print(type(df[col_name])) 」、「print(type(df[[col_name]])) 」を入力して確認してみてください。
# Select single column of dataframe using [] => DataFrame([data, index, columns, dtype, copy])
col_name = 'category_name'
print(df[col_name])
# Select mutiple columns
col_names = ['category_name','page_view']
print(df[col_names])
図4は実行結果です。
行3のprint()では列「category_name」のみ表示されています。
行6のprint()では複数の列「category_name, page_view」が表示されています。
TIP1:
DataFrameの行、列を選択してスライスするには?
DataFrameの「[]」にはレコード(行)の範囲(start:end)を指定してDataFrameのデータをスライスすることもできます。
たとえば、DataFrameの「行2-3」のレコードを選択するには「df[2:4]」のように記述します。「4」は選択単位に含まれません。
また、「df.head(3)」と同じことを範囲指定で行うには「df[0:3]」、「df[:3]」のように記述します。
同様に、「df.tail(1)」、「df.tail(2)」と同じことを範囲指定で行うには「df[-1:]」、「df[-2:]」のように記述します。
# TIP1:
# Select rows
print(df)
print('-----------------------')
print(df[0:3]) # Select rows 0,1,2 (row3 is excluded) => df.head(3)
print()
print(df[:3]) # Select rows 0, 1, 2 (row3 is excluded) => df.head(3)
print()
print(df[-1:]) # Select the last row => df.tail(1)
print()
print(df[-2:]) # Select the last 2 rows => df.tail(2)
print()
print(df[2:4]) # Select rows 2, 3 (row4 is excluded) => Slicing
print()
図TIP1は実行結果です。
df[start:end]の範囲指定は、DataFrameのデータをスライスするときに利用すると便利です。
DataFrameの先頭、もしくは終端を基準にデータを選択するときは、範囲指定ではなく、df.head()、df.tail()を使った方が簡単です。
-
loc[]でDataFrameの列を選択してデータを取得する
行2-3ではDataFrameのloc()メソッドで列を指定してデータ(Series)を取得しています。
loc()の引数1に「:」を指定するとSeries(全行)が選択範囲になります。
行5-6ではloc()メソッドで複数の列を指定してデータ(Series)を取得しています。
loc()の引数1に「:」を指定しているのでSeries(全行)が選択範囲になります。
ちなみに、DataFrameの特定の列のSeriesを選択するには、loc[]よりDataFrameの[]を使用した方が簡単です。
つまり、「df.loc[:, 'category_name']」と「df['category_name']」は同じ結果になります。
# Select all rows / single column
col_name = 'category_name'
print(df.loc[:, col_name]) # If ':' is provided, then it will select all rows
# Select all rows / multiple columns
col_names = ['category_name','page_view']
print(df.loc[:, col_names]) # If ':' is provided, then it will select all rows
図5は実行結果です。
行3のprint()では列「category_name」のSeriesが表示されています。
行6のprint()では列「catetofy_name, page_view」のSeriesが表示されています。
-
loc[]でDataFrameの全列を選択してデータを取得する
行2-3では、DataFrameのloc()メソッドでレコード(行)のindex番号と全列を選択してデータを取得しています。
loc[]の引数1ではレコード(行)のindex番号(2)を指定しています。
引数2では「:」を指定しているので全列が選択の対象になります。
行5ではloc()メソッドの引数1と引数2に「:」を指定しているのでDataFrameの全行と全列が選択の対象になります。
つまり、「print(df)」と同じ結果になります。
引数の「:」の指定ですが、Accessなどのデータベースの知識がある人は、SQLのSELECTコマンドの「*」に相当するとイメージすれば分かりやすいと思います。
# Select single row / all columns
row_index = 2
print(df.loc[row_index, :])
# Select all rows / all columns
print(df.loc[:, :])
図6は実行結果です。
行3のprint()ではindexの番号(2)の全列が表示されています。
行5のprint()ではDataFrameの全データが表示されています。
TIP2:
DataFrameの列にindexを設定して元に戻すには?
データ件数が多いときはDataFrameのindex番号(0-4)を使うのではなく、ユニークな列をindexに設定してそのindexで検索します。
たとえば、列「category_name」の値がユニークなのでこの列をindexに設定して、loc()メソッドで検索するときは「category_name」で検索します。
「Python」のレコード(行)を検索するときは「df.loc['Python']」のように記述します。
DataFrameの任意の列をindexに設定するときはset_index()メソッドを使用します。
Pandasのデフォルトのindexに戻したいときはreset_index()メソッドを使用します。
# TIP2: Set index / Reset index
df.set_index('category_name', inplace=True)
print(df)
index_key = 'Python'
print(df.loc[index_key])
df.reset_index(inplace=True)
print(df)
図TIP2は実行結果です。
set_index('category_name')を実行するとその列「category_name」が先頭に表示されます。
reset_index()を実行するとPandasのデフォルトの列「index」が追加されて先頭に表示されます。
列「category_name」は通常の列として表示されます。
-
loc[]でDataFrameの行/列を選択してデータを取得する
行2-4ではDataFrameのloc()メソッドでDataFrameの行/列を指定して「値」を取得しています。
loc[]の引数1ではindex番号(1)の行を指定しています。
引数2では列「category_name」を指定しています。
DataFrameから特定の行/列を指定して値を取得するときはloc[]より後述するat[]の方が便利です。
行6-8ではloc()メソッドで複数の行/列を指定してデータを取得しています。
つまり、DataFrameからデータをスライスしています。
# Select single row / single column
row_index = 1
col_name = 'category_name'
print(df.loc[row_index, col_name])
# Select (Slice) multiple rows / multiple columns
row_indexes = [3,4]
col_names = ['category_name','page_view']
print(df.loc[row_indexes, col_names])
図7は実行結果です。
行4のprint()ではindex番号(1)の列「category_name」の値「jQuery」が表示されています。
行8のprint()ではindex番号(3,4)の列「category_name, page_view」の値が表示されています。
TIP3:
DataFrameのloc()とiloc()の違いとは?
loc()とiloc()はDataFrameから行/列の範囲を指定してデータをスライスすることができます。
loc()で行/列の範囲指定を行うときは「loc[start:end, start:end]」のように記述します。
引数1が行の範囲、引数2が列の範囲になります。
loc()で範囲を指定するときは行/列ともラベル名で指定します。
loc()で行/列の範囲を指定するとき、「df.loc[start:end, 'start':'end']」の「start, end」ともラベル名なので選択範囲に含まれます。
DataFrameのindexが数字ではなく英文字の「a-e」のときを想定すると理解しやすいと思います。
たとえば、loc['a':'c', :]と記述したときは行の'c'も選択範囲に含まれます。
iloc()で行/列の範囲指定を行うときは「iloc[start:end, start:end]」のように記述します。
引数1が行の範囲、引数2が列の範囲になります。
loc()と異なり、iloc()のときは行/列とも数字で位置/範囲を指定します。
iloc()で行/列の範囲を指定するとき、「df.iloc[1:2, 0:3]」の行の「2」は選択範囲に含まれますが、列の「3]は選択範囲に含まれません。
まとめると、loc()は行/列ともラベル名を指定します。
そして、iloc()は行/列とも数字で位置を指定します。
# TIP3: loc[start:end, start:end], iloc[start:end, start:end] => slicing
print(df)
print('--------------------')
print(df.loc[:, 'category_name']) # Select all rows and single column
#print(df.iloc[:, 'category_name']) # Error
print(df.loc[:, ['category_name','page_view']]) # Select all rows and multiple columns
print(df.loc[:, 'category_name':'exclude_me']) # Select all rows and slicing columns
print()
print(df.loc[1:3, :]) # Select rows 1, 2, 3 (include row3) and all columns
print()
print(df.iloc[1:3, :]) # Select rows 1, 2 (exclude row3) and all columns
print()
#print(df.loc[1:3, 0]) # Error
print(df.iloc[1:3, 0]) # Select rows 1,2 (exclude row3) and column 0
print()
print(df.iloc[1:3, 0:3]) # Select rows 1,2 (exclude row3) and columns 0, 1, 2 (exclude col3)
図TIP3[1]は前半部分の実行結果です。
loc()の場合、「loc[start:end, start:end]」のように行/列の範囲を指定したとき、「end」は行/列とも選択範囲に含まれます。
図TIP3[2]は後半部分の実行結果です。
iloc()の場合、「iloc[start:end, start:end]」のように行/列の範囲を指定したとき、行の「end」は選択範囲に含まれますが、列の「end」は選択範囲に含まれません。
-
loc[]でDataFrameの列をbool型で選択してデータを取得する
行2-4ではloc()メソッドの引数2にbool型で列を指定しています。
Trueに対応する列が選択対象で、Falseに対応する列が非選択の対象になります。
ここでは列「category_name, page_view」を選択しています。
# Select (Slice) multiple rows / multiple columns : a boolean array
row_indexes = [2,3]
col_bool_array = [True, True, False, False]
print(df.loc[row_indexes, col_bool_array])
図8は実行結果です。行4のprint()ではindex番号(2,3)の列「category_name, page_view」の値が表示されています。
-
at[], iat[]でDataFrameの行/列を指定して値を取得する
行4ではDataFrameのat()メソッドで行/列を指定して値を取得しています。
at()の引数1には行のindex番号を指定します。
引数2には列名を指定します。
行5ではDataFrameのloc()メソッドで列「category_name」のSeries(特定の列の全行の意味)を選択してからat()メソッドで列名を指定して値を取得しています。
行8ではDataFrameのiat()メソッドで行/列を指定して値を取得しています。
iat()の引数1にはindex番号を指定します。
引数2には列の番号を指定します。
行9ではDataFrameのloc()メソッドで列「category_name」のSeriesを選択してからiat()メソッドで列番号を指定して値を取得しています。
# Using df.at[row, col], df.iat[row, col]
row_index = 2
col_name = 'category_name'
print(f'df.at[row,col] = {df.at[row_index, col_name]}')
print(f'df.loc[row].at[col] = {df.loc[row_index].at[col_name]}')
print()
col_index = 0
print(f'df.iat[row,col] = {df.iat[row_index, col_index]}')
print(f'df.loc[row].iat[col] = {df.loc[row_index].iat[col_index]}')
図9は実行結果です。
at()、iat()ともDataFrameのindex番号(2)の列「category_name」の値を取得して表示しています。
-
iterrows()でDataFrameのレコード(行)を1件ずつ取得して処理する
行2-4ではDataFrameのiterrows()メソッドでDataFrameから1件ずつレコード(行)を取得して処理しています。
行2のforループではiterrows()で取得したレコードのindex番号とレコードの内容を変数index, rowに格納しています。
iterrows()からレコード(行)を取得するときは、必ずindexとペアで取得する必要があります。
行4は変数rowに格納されているレコード(行)の列を取得して表示しています。
# Using iterrows() Iterate over DataFrame rows as (index, Series) pairs.
for index, row in df.iterrows():
#print(type(row))
print(f"{row['category_name']}\t {row['page_view']}\t {row['exclude_me']}\t {row['date_added']}")
図10は実行結果です。
DataFrameのデータがレコード(行)毎に表示されています。
-
items()でDataFrameのSeries(列の全行)を1件ずつ取得して処理する
行2-5ではitems()メソッドでDataFrameのSeries(列の全行)を取得して処理しています。
行2のforループではitems()で取得した列名とSeriesを変数labelとcontentに格納しています。
変数labelに列名が格納されます。
変数contentにはSeries(列毎の全行)が格納されます。
行3では列名を表示しています。
行5ではSeriesをレコード(行)毎に改行して表示しています。
# Using DataFrame.items() Iterate over (column name, Series) pairs.
for label, content in df.items():
print(f'label: {label}')
print('-----------------------------')
print(f'{content}', sep='\n')
図11は実行結果です。
DataFrameの列毎にSeries(列の全行)が表示されています。