Python {Article009}

ようこそ「Python」へ...

Python PandasのDataFrameからデータを選択して取得するには【Pandas】

ここでは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の情報を取得する

  1. まずは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)
    click image to zoom!
    図1
    図1は実行結果です。 DataFrameの列名と列の値がレコード(行)単位に表示されています。 レコード(行)の先頭に表示されている数字(0-4)はレコード(行)のindex番号です。 index番号はPandasがデータをロードしたときに自動的に作成します。 このindex番号は後述するiloc[]、iat[]などで使用します。
  2. 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}')
    click image to zoom!
    図2
    図2は実行結果です。 DataFrameの列名、列のデータ型などが表示されています。 また、レコード(行)件数と列件数も表示されています。

DataFrameから行/列を選択してデータを取得する

  1. 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))
    click image to zoom!
    図3
    図3は実行結果です。 DataFrameの先頭レコード(行)と最終レコード(行)が表示されています。
  2. 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])
    click image to zoom!
    図4
    図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()
    click image to zoom!
    図TIP1
    図TIP1は実行結果です。 df[start:end]の範囲指定は、DataFrameのデータをスライスするときに利用すると便利です。 DataFrameの先頭、もしくは終端を基準にデータを選択するときは、範囲指定ではなく、df.head()、df.tail()を使った方が簡単です。
  3. 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
    click image to zoom!
    図5
    図5は実行結果です。 行3のprint()では列「category_name」のSeriesが表示されています。 行6のprint()では列「catetofy_name, page_view」のSeriesが表示されています。
  4. 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[:, :])
    click image to zoom!
    図6
    図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)
    click image to zoom!
    図TIP2
    図TIP2は実行結果です。 set_index('category_name')を実行するとその列「category_name」が先頭に表示されます。 reset_index()を実行するとPandasのデフォルトの列「index」が追加されて先頭に表示されます。 列「category_name」は通常の列として表示されます。
  5. 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])
    click image to zoom!
    図7
    図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)
    click image to zoom!
    図TIP3[1]
    図TIP3[1]は前半部分の実行結果です。 loc()の場合、「loc[start:end, start:end]」のように行/列の範囲を指定したとき、「end」は行/列とも選択範囲に含まれます。
    click image to zoom!
    図TIP3{2]
    図TIP3[2]は後半部分の実行結果です。 iloc()の場合、「iloc[start:end, start:end]」のように行/列の範囲を指定したとき、行の「end」は選択範囲に含まれますが、列の「end」は選択範囲に含まれません。
  6. 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])
    click image to zoom!
    図8
    図8は実行結果です。行4のprint()ではindex番号(2,3)の列「category_name, page_view」の値が表示されています。
  7. 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]}')
    click image to zoom!
    図9
    図9は実行結果です。 at()、iat()ともDataFrameのindex番号(2)の列「category_name」の値を取得して表示しています。
  8. 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']}")
    click image to zoom!
    図10
    図10は実行結果です。 DataFrameのデータがレコード(行)毎に表示されています。
  9. 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')
    click image to zoom!
    図11
    図11は実行結果です。 DataFrameの列毎にSeries(列の全行)が表示されています。