DataFrameオブジェクトを生成する方法とその際に指定可能なオプション、DataFrameから特定の行や列、個別の要素をiloc属性とloc属性で選択する方法を見ていきます。
本シリーズ「Pythonデータ処理入門」は、Pythonの基礎をマスターした人を対象に以下のような、Pythonを使ってデータを処理しようというときに便利に使えるツールやライブラリ、フレームワークの使い方の基礎を説明するものです。
なお、本連載では以下のバージョンを使用しています。
前回は1次元配列を扱うためのSeriesオブジェクトについて見てきました。今回は2次元配列を扱うためのpandas.DataFrameクラスを取り上げます。DataFrameオブジェクトは、今もいったように2次元のデータを扱うためのオブジェクトで、Seriesオブジェクトと同様に、行と列を識別するために数値とは別のラベルを付加できます。
DataFrameオブジェクトは第1回で紹介したpandas.read_csv関数などを使って作成可能ですが、ここではpandas.DataFrameコンストラクタを呼び出す方法を見てみましょう。
pandas.DataFrame(data=None, index=None, columns=None, dtype=None, copy=None)
2次元配列であるDataFrameクラスのインスタンスを生成する。パラメーターは以下の通り。
以下ではDataFrameオブジェクトを作成しながら、その基本的な特徴を見ていくことにしましょう。
DataFrameオブジェクトは行と列からなる2次元のデータ構造です。従って、2次元のリスト(リストのリスト)やNumPyのndarrayオブジェクトを渡すのが一番分かりやすい作成例といえるでしょう。以下に示します。
import pandas as pd
import numpy as np
l = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
a = np.array(l)
df = pd.DataFrame(l)
print(df)
# 出力結果:
# 0 1 2
#0 0 1 2
#1 3 4 5
#2 6 7 8
df = pd.DataFrame(a)
print(df) # 出力結果は上と同じなので省略
この例では、2次元のリストからNumPyのndarrayオブジェクトを生成し、その両者を基にDataFrameオブジェクトを生成しています。
出力結果の先頭行(0 1 2)と左端(0 1 2)にも注目してください。これらはDataFrameオブジェクトの列や行、または個々の要素にアクセスする際に使用できる軸ラベルと呼ばれるものです。列を選択するのに使用するのが列ラベル、行を選択するのに使われるのが行ラベルです。なお、行については「インデックス」と呼ぶこともあります。軸ラベルには整数や文字列などを指定できますが、上のように特に指定しなければ0から始まる整数値が割り当てられます。
話を元に戻しましょう。辞書からDataFrameオブジェクトを生成することも可能です。以下に例を示します。
d = {'col0': [0, 3, 6], 'col1': [1, 4, 7], 'col2': [2, 5, 8]}
df = pd.DataFrame(d)
print(df)
# 出力結果:
# col0 col1 col2
#0 0 1 2
#1 3 4 5
#2 6 7 8
d = {'col0': pd.Series([0, 3, 6]), 'col1': pd.Series([1, 4, 7]),
'col2': pd.Series([2, 5, 8])}
df = pd.DataFrame(d)
print(df) # 出力結果は上と同じなので省略
この例ではまず'col0'、'col1'、'col2'をキーとしてそれらの値をリストとする辞書を作成して、そこからDataFrameオブジェクトを生成しています。その後、リストではなくSeriesオブジェクトを値とする他は同様な辞書を作成して、それを基にDataFrameオブジェクトを生成しています。
覚えておくべきは辞書のキーが列ラベルとなっている点です(出力結果の先頭行の「col0 col1 col2」という部分)。これについては後述しますが、列ラベルはDataFrameオブジェクトから特定の列の内容を取り出す際に使えます。
print(df['col0'])
# 出力結果:
#0 0
#1 3
#2 6
#Name: col0, dtype: int64
次のような辞書を要素とするリストからもDataFrameオブジェクトは生成可能です。
d = [{'col0': 0, 'col1': 1, 'col2': 2}, {'col0': 3, 'col1': 4, 'col2': 5},
{'col0': 6, 'col1': 7, 'col2': 8}]
df = pd.DataFrame(d)
print(df)
この例では、1つの辞書に各列('col0'、'col1'、'col2')の値をキー/値形式でまとめて、それらを要素とするリストを作成しています。これをpandas.DataFrameコンストラクタに渡すと、先ほどと同様なDataFrameオブジェクトが生成されます。
このように、pandas.DataFrameコンストラクタのdataパラメーターにはさまざまな形式でデータを渡せます。ここで見たのはかなり基本的なものだけなので、詳細についてはpandasのドキュメント「Intro to data structures」を参照してください。
indexパラメーターは特定の行を指定する際に使用するインデックス(行ラベル)を指定するものです。省略すると整数インデックスが与えられるのはSeriesオブジェクトと同様です。
以下を見てください。
df = pd.DataFrame([[0, 1, 2], [3, 4, 5]])
print(df)
# 出力結果:
# 0 1 2
#0 0 1 2
#1 3 4 5
ここでは2行3列のDataFrameオブジェクトを作成していますが、indexパラメーターは特に指定していません。そのため、インデックス(左端)には0と1と整数インデックスが縦に表示されています。このインデックスはiloc属性などで特定の行の内容を取り出すのに使えます。
print(df.iloc[1])
# 出力結果:
#0 3
#1 4
#2 5
#Name: 1, dtype: int64
indexパラメーターに文字列のリストなどを渡すことで、行にアクセスするときにそれらを行ラベルとして使えるようになります。以下はその例です。
df = pd.DataFrame([[0, 1, 2], [3, 4, 5]], index=['row0', 'row1'])
print(df)
# 出力結果:
# 0 1 2
#row0 0 1 2
#row1 3 4 5
この例では「index=['row0', 'row1']」のようにindexパラメーターに文字列のリストを渡しているので、出力結果の左端にはリストの要素である'row0'と'row1'がインデックス(行ラベル)として表示されています。これを実際に使って第1行('row1'行)の内容を取り出してみましょう。
print(df.loc['row1'])
# 出力結果:
#0 3
#1 4
#2 5
#Name: row1, dtype: int64
ここではloc属性に'row1'を指定して、該当行の内容を取り出しています。先ほど整数インデックスのときにはiloc属性を使用しましたが、上のように行ラベルを使うときにはloc属性を使用します(文字列の軸ラベルを設定していない場合、loc属性に整数インデックスを渡すことは可能ですが、ドキュメントによると、それは文字列などを使った行ラベルと同様に解釈されるのであって、整数インデックスとして解釈されるわけではありません)。
ところで、indexパラメーターにはもう1つの機能があります。それはDataFrameオブジェクトを作成する際の元データのフィルタリングです。言い換えると、DataFrameオブジェクトを作成する際に、そこに格納するデータを選択するのに使えるということです。
例を見てみましょう。
df = pd.DataFrame([[0, 1, 2], [3, 4, 5], [6, 7, 8]],
index=['row0', 'row1', 'row2'])
print(df)
# 出力結果:
# 0 1 2
#row0 0 1 2
#row1 3 4 5
#row2 6 7 8
ここでは「index=['row0', 'row1', 'row2']」と指定して、DataFrameオブジェクトを生成しています。
そして、今作成したdfオブジェクトを基に別のDataFrameオブジェクトを作成してみます。ただし、indexパラメーターの指定は先ほどとは異なり「index=['row1', 'row2', 'row3']」となっています。
df2 = pd.DataFrame(df, index=['row1', 'row2', 'row3'])
print(df2)
この結果はどうなるでしょう。以下はVisual Studio Codeでこのコードを実行したところです。
ご覧の通り、元データの第0行はなくなり、'row3'行が新たに作成されて、その行の値は全てNaNになっています。これが意味するのは、「index=['row1', 'row2', 'row3']」と指定したことで、元データでこれに合致する'row1'行と'row2'行が選択され、指定にない'row0'行がなくなったということです。さらに'row3'行は存在していないので新たにその行が作られたが、元データには存在しない要素なのでその値がNaNになったということです。頻繁に使うことはないでしょうが、誰かが書いたコードにこうした記述があったときに「ん? 何これ?」とならないようにここでは紹介しておきました(次に説明するcolumnsパラメーターでも同様です)。
indexパラメーターが行ラベルの指定で、columnsパラメーターが列ラベルの指定であることを除けば、両者は同様に機能します。指定を省略したときには、列ラベルは整数となります。
df = pd.DataFrame([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
print(df)
# 出力結果:
# 0 1 2
#0 0 1 2
#1 3 4 5
#2 6 7 8
上の例では、columnsパラメーターの指定を省略しているので列ラベルが整数値で0、1、2になっていることが分かります。以下はcolumnsパラメーターを指定する例です。
df = pd.DataFrame([[0, 1, 2], [3, 4, 5], [6, 7, 8]],
columns=['col0', 'col1', 'col2'])
print(df)
# 出力結果:
# col0 col1 col2
#0 0 1 2
#1 3 4 5
#2 6 7 8
この例では、「columns=['col0', 'col1', 'col2']」と指定しているので出力結果の最初の行には指定した文字列が列ラベルとして表示されています。
列ラベルはDataFrameオブジェクトの特定の列を選択する際に使用できます。ただし、特定の列を選択するだけであれば、iloc属性やloc属性を使用せず、次のようにブラケット「[]」の中に列ラベルを直接指定するのが一般的でしょう。
print(df['col1'])
# 出力結果:
#0 1
#1 4
#2 7
#Name: col1, dtype: int64
loc属性を使って同じことをするのであれば、次のようにします(ここでは整数インデックスではなく文字列のラベルを指定するのでloc属性を使っています)。
print(df.loc[:, 'col1'])
# 出力結果:
#0 1
#1 4
#2 7
#Name: col1, dtype: int64
「df.loc[:, 'col1']」の最初にある単独のコロン「:」はどの行を選択するかの指示で、Pythonのスライスにおける全ての要素を意味する指定と同様です。この場合は全ての行を意味します。そして、'col1'がどの列を選択するかの指定で、この場合はもちろん'col1'列を選択することを意味します。その結果は'col1'列の全ての行が表示されます(なお、loc属性やiloc属性についてはこの後で簡単に紹介し、後続の回で詳しく解説する予定です)。
pandas.DataFrameコンストラクタに渡した元データが列ラベル情報を持っている場合に、columnsパラメーターを指定すると、その値に応じて元データのどの列をDataFrameオブジェクトに格納するかが決まります(先ほど、indexパラメーターで見たのと同様)。以下に例を示します。
df = pd.DataFrame([[0, 1, 2], [3, 4, 5], [6, 7, 8]],
columns=['col0', 'col1', 'col2'])
print(df)
# 出力結果:
# col0 col1 col2
#0 0 1 2
#1 3 4 5
#2 6 7 8
df2 = pd.DataFrame(df, columns=['col1', 'col2', 'col3'])
print(df2)
# 出力結果:
# col1 col2 col3
#0 1 2 NaN
#1 4 5 NaN
#2 7 8 NaN
行と列が異なりますが、やっていることは先ほどのindexパラメーターの指定例と同様なので説明は不要でしょう。
また、dtypeパラメーターとcopyパラメーターについては前回のpandas.Seriesコンストラクタの説明で取り上げているので「Seriesオブジェクトに格納できるもの」および「copyパラメーターの指定」を参照してください。
Copyright© Digital Advantage Corp. All Rights Reserved.