前回、「Pandas の DataFrame の基本的な使い方 - akiyoko blog」と題して pandas.DataFrame の基本的な使い方のまとめをしましたが、今回は、pandas.DataFrame の操作の中でも一番よく使うであろう「列の抽出(射影)方法」および「行の抽出(選択)方法」についてのまとめをしたいと思います。
先に結論を書くと、
列の抽出(射影)方法には以下の5パターンがあります。
- 1−1)['カラム名']
- 1−2).カラム名
- 1−3)[['カラム名', 'カラム名']]
- 1−4)[[カラム番号]]
- 1−5)[[カラム番号, カラム番号]]
行の抽出(選択)方法には以下の4パターンがあります。
- 2−1)head() / tail()
- 2−2) [indexの始点:indexの終点]
- 2−3)[条件]
- 2−4)query('条件')
行と列を同時に指定して抽出する方法としては以下の3パターンがあります。
射影と選択
まず、列の抽出は「射影」、行の抽出は「選択」と呼ばれます。
概念図は以下のようになります。
前提条件
ローカルの実行環境は以下の通りです。
- MacOS Sierra 10.12.3
- Python 2.7.12 (Anaconda 4.2.0)
- Jupyter Notebook 4.2.0
- pandas 0.18.1
事前準備
まずは事前準備です。
前回 同様、日経平均のデータ(n225.csv)のサンプルデータを読み込んでおきます。
import pandas as pd # 10行だけ表示するおまじない pd.options.display.max_rows = 10 # サンプルデータを読み込む df = pd.read_csv('n225.csv', index_col='Date', parse_dates=True, usecols=['Date', 'Open', 'Volume', 'Adj Close']) df = df.sort_index() df
1.列の抽出(射影)
1−1)['カラム名']
列へアクセスする場合の基本形。
戻り値として pandas.Series が取得できます。
# 列へアクセスするための基本形 df['Open'] # この形であればスペースを含むカラム名もOK # df['Adj Close']
Date 2016-01-04 18818.580078 2016-01-05 18398.759766 2016-01-06 18410.570312 2016-01-07 18139.769531 2016-01-08 17562.230469 ... 2016-12-26 19394.410156 2016-12-27 19353.429688 2016-12-28 19392.109375 2016-12-29 19301.039062 2016-12-30 18997.679688 Name: Open, dtype: float64
1−2).カラム名
列にアクセスする場合に「df.column_A」とシンプルに書くこともできますが、このパターンではスペースを含むカラム名が扱えないのであまり使われることはないと思います。
# 最もシンプルなのは .を使うパターンだが、スペースを含むカラム名は扱えない df.Adj Close # 以下のように '' や "" で囲んでも SyntaxError になるのでNG df.'Adj Close'
SyntaxError: invalid syntax
1−3)[['カラム名', 'カラム名']]
複数カラムを指定する場合はこのように書くことができます。
この場合は pandas.DataFrame が得られます。
df[['Open', 'Adj Close']]
2.行の抽出(選択)
2−1)head() / tail()
一番シンプルなのは、head() や tail() を使うパターンでしょうか。
head() は先頭から、tail() は行末から任意の数だけ行を取得できます。
# 先頭から10行目までを抽出 df.head(10)
引数を指定しないと 5行分取得できます。
# 行末から5行を抽出
df.tail()
2−2) [indexの始点:indexの終点]
index の始点と終点で行をスライスするには、このパターンを使います。
まずは、行番号で指定する場合。
# 2行目から3行目までを抽出 df[1:3]
次に、index のラベル名で指定する場合。
# DatetimeIndex の場合は '20160107' のように文字列を指定してもいい感じに変換してくれるっぽい df['20160107':'20160114'] # なお、以下のように指定すると列の抽出になるので KeyError となる # df['20160107']
ちなみに、DatetimeIndex の場合は、存在しない日付を指定しても KeyError になりません。
df['20160101':'20160110']
起点と終点を index のラベル名で指定するパターンは、この例の方が分かりやすいかもしれません。
df2 = pd.DataFrame([[1, 11, 111], [2, 22, 222], [3, 33, 333], [4, 44, 444]], index=['one', 'two', 'three', 'four'], columns=['A', 'B', 'C']) df2['two':'four']
2−3)[条件]
行の抽出の基本形はこのパターンです。
条件の部分には boolean vector で指定します。
df[df['Adj Close'] > 19400]
index の条件を指定する場合はこのように書けます。
df[df.index < '20160110']
panads.date_range() で作成した DatetimeIndex の範囲内の行を絞り込む場合は、DatetimeIndex.isin() を使ってこう書くことができます。
# 以下は df['20160101':'20160110'] と同じ結果になる span = pd.date_range('2016-01-01', periods=10) df[df.index.isin(span)]
(参考)pandas.DatetimeIndex.isin — pandas 0.21.1 documentation
複数AND条件の場合はこう書くことができます。
(参考)Indexing and Selecting Data — pandas 0.21.1 documentation
df[(df.index.month == 3) & (df.index.day < 10)]
複数OR条件の場合はこう書くことができます。
df[(df.index.is_month_start) | (df.index.is_month_end)]
ちなみに、DatetimeIndex の月初・月末判定については以下を参照。
(参考)pandas.DatetimeIndex — pandas 0.21.1 documentation
2−4)query('条件')
query() を使っても 2−3)と同様に特定条件の行を抽出できます。
df.query('Volume == 173000')
しかしながら、ラベル名にスペースが含まれる場合に SyntaxError が発生してしまいます。今のところこの回避索が分からないので、汎用的に使うことができません。
df.query('Adj Close == 173000')
SyntaxError: invalid syntax
3.行・列を同時指定して抽出
loc()、iloc()、および ix() は、行と列を同時に指定することができます。
3−1)loc()
loc() はラベル名で指定します。
index名、column名の順で指定します。
まず、単行・単列を抽出する場合。
df.loc['20160107', 'Volume']
163000.0
複数行・複数列を抽出する場合は、「:」を使って範囲指定します。
df.loc['20160104':'20160107', 'Volume':'Adj Close']
列の指定を省略することも可能です。その場合は、単に行の抽出ということになります。
df.loc['20160107':'20160114'] # 以下と等価 # df.loc['20160107':'20160114', :]
行の抽出条件を指定したくない場合は、行の指定は省略できないので「:」を指定します。その場合には、単に列の抽出ということになります。
df.loc[:, 'Volume']
Date 2016-01-04 136000 2016-01-05 128300 2016-01-06 142200 2016-01-07 163000 2016-01-08 178800 ... 2016-12-26 0 2016-12-27 110200 2016-12-28 77700 2016-12-29 0 2016-12-30 117800 Name: Volume, dtype: int64
飛び飛びの index, column を指定したい場合は、それぞれ [] を使います。
df2.loc[['one', 'three'], ['A', 'C']] # なお、DatetimeIndex の場合は pd.to_datetime で変換する必要があるっぽいので面倒・・ # df.loc[pd.to_datetime(['20160107', '20160114']), ['Open', 'Adj Close']]
3−2)iloc()
iloc() は数値で指定します。
index番号、column番号の順で指定します。
まず、単行・単列を抽出する場合。
df.iloc[0, 0]
18818.580077999999
複数行・複数列を抽出する場合は、「:」を使って範囲指定します。
df.iloc[1:3, 1:2]
列の指定を省略することも可能です。その場合は、単に行の抽出ということになります。
df.iloc[1:3] # 以下と等価 # df.iloc[1:3, :]
行の抽出条件を指定したくない場合は、行の指定は省略できないので「:」を指定します。その場合には、単に列の抽出ということになります。
df.iloc[:, 1:3]
飛び飛びの index, column を指定したい場合は、それぞれ [] を使います。
df.iloc[[0, 2], [0, 2]]
3−3)ix()
ix() なら、ラベル名と数値のいずれでも利用することができます。
df.ix['20160107', 'Volume'] df.ix['20160104':'20160107', 'Volume':'Adj Close'] df.ix['20160107':'20160114'] df.ix['20160107':'20160114', :] df.ix[:, 'Volume'] df.ix[0, 0] df.ix[1:3, 1:2] df.ix[1:3] df.ix[1:3, :] df.ix[:, 1:3]
参考
Pandas について本格的に勉強するならこちらの本を。
Jypyter Notebook の勉強をするならこの本を。
pandas.DataFrame の列の抽出と行の抽出についての公式まとめページはこちら。
その他、こちらも参考に。