akiyoko blog

akiyoko の IT技術系ブログです

pandas.DataFrame の列の抽出(射影)および行の抽出(選択)方法まとめ

前回、「Pandas の DataFrame の基本的な使い方 - akiyoko blog」と題して pandas.DataFrame の基本的な使い方のまとめをしましたが、今回は、pandas.DataFrame の操作の中でも一番よく使うであろう「列の抽出(射影)方法」および「行の抽出(選択)方法」についてのまとめをしたいと思います。


先に結論を書くと、
列の抽出(射影)方法には以下の5パターンがあります。

行の抽出(選択)方法には以下の4パターンがあります。

行と列を同時に指定して抽出する方法としては以下の3パターンがあります。


 

射影と選択

まず、列の抽出は「射影」、行の抽出は「選択」と呼ばれます。
概念図は以下のようになります。

f:id:akiyoko:20141107171430p:plain

前提条件

ローカルの実行環境は以下の通りです。

  • 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

f:id:akiyoko:20170403070357p:plain:w250



 

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']]

f:id:akiyoko:20170403070458p:plain:w200


 

1−4)[[カラム番号]]

カラム番号で指定する場合はこう書きます。
この場合も pandas.DataFrame が得られます。

df[[0]]

f:id:akiyoko:20170403071159p:plain:w150


 

1−5)[[カラム番号, カラム番号]]

カラム番号を複数指定する場合は、カンマで列挙します。

df[[0, 2]]

f:id:akiyoko:20170403071314p:plain:w200


 

2.行の抽出(選択)

2−1)head() / tail()

一番シンプルなのは、head() や tail() を使うパターンでしょうか。
head() は先頭から、tail() は行末から任意の数だけ行を取得できます。

# 先頭から10行目までを抽出
df.head(10)

f:id:akiyoko:20170403071552p:plain:w250


引数を指定しないと 5行分取得できます。

# 行末から5行を抽出
df.tail()

f:id:akiyoko:20170403071608p:plain:w250


 

2−2) [indexの始点:indexの終点]

index の始点と終点で行をスライスするには、このパターンを使います。

まずは、行番号で指定する場合。

# 2行目から3行目までを抽出
df[1:3]

f:id:akiyoko:20170403071840p:plain:w250


次に、index のラベル名で指定する場合。

# DatetimeIndex の場合は '20160107' のように文字列を指定してもいい感じに変換してくれるっぽい
df['20160107':'20160114']

# なお、以下のように指定すると列の抽出になるので KeyError となる
# df['20160107']

f:id:akiyoko:20170403071932p:plain:w250


ちなみに、DatetimeIndex の場合は、存在しない日付を指定しても KeyError になりません。

df['20160101':'20160110']

f:id:akiyoko:20170403071932p:plain:w250


起点と終点を 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']

f:id:akiyoko:20170403215756p:plain:w100


 

2−3)[条件]

行の抽出の基本形はこのパターンです。
条件の部分には boolean vector で指定します。

df[df['Adj Close'] > 19400]

f:id:akiyoko:20170403072648p:plain:w250


index の条件を指定する場合はこのように書けます。

df[df.index < '20160110']

f:id:akiyoko:20170403072723p:plain:w250


panads.date_range() で作成した DatetimeIndex の範囲内の行を絞り込む場合は、DatetimeIndex.isin() を使ってこう書くことができます。

# 以下は df['20160101':'20160110'] と同じ結果になる
span = pd.date_range('2016-01-01', periods=10)
df[df.index.isin(span)]

f:id:akiyoko:20170403072723p:plain:w250

(参考)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)]

f:id:akiyoko:20170403072829p:plain:w250


複数OR条件の場合はこう書くことができます。

df[(df.index.is_month_start) | (df.index.is_month_end)]

f:id:akiyoko:20170403072918p:plain:w250

ちなみに、DatetimeIndex の月初・月末判定については以下を参照。
(参考)pandas.DatetimeIndex — pandas 0.21.1 documentation


 

2−4)query('条件')

query() を使っても 2−3)と同様に特定条件の行を抽出できます。

df.query('Volume == 173000')

f:id:akiyoko:20170403072953p:plain:w250


しかしながら、ラベル名にスペースが含まれる場合に 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']

f:id:akiyoko:20170403073138p:plain:w200


列の指定を省略することも可能です。その場合は、単に行の抽出ということになります。

df.loc['20160107':'20160114']

# 以下と等価
# df.loc['20160107':'20160114', :]

f:id:akiyoko:20170403073253p:plain:w250


行の抽出条件を指定したくない場合は、行の指定は省略できないので「:」を指定します。その場合には、単に列の抽出ということになります。

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']]

f:id:akiyoko:20170403073558p:plain:w100


 

3−2)iloc()

iloc() は数値で指定します。
index番号、column番号の順で指定します。


まず、単行・単列を抽出する場合。

df.iloc[0, 0]
18818.580077999999

複数行・複数列を抽出する場合は、「:」を使って範囲指定します。

df.iloc[1:3, 1:2]

f:id:akiyoko:20170403073723p:plain:w120


列の指定を省略することも可能です。その場合は、単に行の抽出ということになります。

df.iloc[1:3]

# 以下と等価
# df.iloc[1:3, :]

f:id:akiyoko:20170403073859p:plain:w200


行の抽出条件を指定したくない場合は、行の指定は省略できないので「:」を指定します。その場合には、単に列の抽出ということになります。

df.iloc[:, 1:3]

f:id:akiyoko:20170403073924p:plain:w200


飛び飛びの index, column を指定したい場合は、それぞれ [] を使います。

df.iloc[[0, 2], [0, 2]]

f:id:akiyoko:20170403074002p:plain:w200


 

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]