この記事について
今までなんとなくで使用していたpandasですが、なんとなくで実装していたコード(日経平均予想のやつです)が汚くメンテナンスが難しくなってきたので、一度ちゃんとpandasでのデータの扱い方をまとめておこうと思って書いたものです。
pandasの公式ドキュメントに Intro to Data Structures というものがあり、基本的にはそこで説明されていることの一部をピックアップして紹介している記事になります。
http://pandas.pydata.org/pandas-docs/stable/dsintro.html
Series: 1次元のデータ
Seriesの作り方
Seriesは1次元のラベル付き配列です。要素はどんな型のデータでも入れることができます。
例えば、日経平均(N225)、S&P500(GSPC)、DAX(GDAXI)という3つの株価指数の10月7日の終値は次のようなものでした。
指数 | 10/7の終値 |
---|---|
N225 | 16860.089844 |
GSPC | 2153.73999 |
GDAXI | 10490.860352 |
このデータをSeriesで1次元の配列のように扱うには、次のようにSeriesを生成します。
# 10月7日の終値のSeriesを作る # 配列から s = pd.Series([16860.089844, 2153.73999, 10490.860352], index=['N225', 'GSPC', 'GDAXI']) # 辞書から s = pd.Series({'N225':16860.089844 , 'GSPC':2153.73999 , 'GDAXI':10490.860352 })
どちらもまったく同じSeriesが作られており、Pythonのprint()関数かJupyter Notebookで中身を確認するとこんな感じのデータになってます。
GDAXI 10490.860352 GSPC 2153.739990 N225 16860.089844 dtype: float64
Seriesはnumpyのndarrayに似ている
Seriesはnumpyのndarrayに似た扱いが可能です。
このように添え字でアクセスできます。Pythonの配列のようなスライスも使えます。
s[0]
10490.860352
こんなことをすると、中央値より大きな値を取り出す、なんてことも簡単にできます。
s[s > s.median()]
N225 16860.089844 dtype: float64
numpyの関数はそのまま使えます。例えば対数や指数を取りたいときも、こんな感じで一発です。
np.log(s)
GDAXI 9.258260 GSPC 7.674961 N225 9.732705 dtype: float64
SeriesはPythonの辞書に似ている
Seriesは辞書にも似ています。辞書のように、ラベルを使って各要素にアクセスできます。
s['N225']
16860.089844
辞書と同様に、in でキーの存在確認なんかもできます。
'FTSE' in s
False
ベクトル的な計算もできます
ベクトル同士の足し算や
s + s
GDAXI 20981.720704 GSPC 4307.479980 N225 33720.179688 dtype: float64
スカラー値との掛け算も。
s * 3
GDAXI 31472.581056 GSPC 6461.219970 N225 50580.269532 dtype: float64
Name属性
Serieseには名前を付けることもできます。このような形で name という引数を渡してあげます。
s = pd.Series({'N225':16860.089844 , 'GSPC':2153.73999 , 'GDAXI':10490.860352 }, name='close')
すると、次のようなSeriesが定義されます。
GDAXI 10490.860352 GSPC 2153.739990 N225 16860.089844 Name: close, dtype: float64
このように、最初に定義した名前にアクセスすることもできます。
s.name
'close'
名前を変えたいときはrenameメソッドを使います。
s.rename('closing_value')
DataFrame: 2次元のデータ
DataFrameの作り方
2次元のデータを扱うには、DataFrameを使用します。イメージとしてはエクセルのシートのようなものが扱えるイメージです。
これは非常に有名なデータ構造なので、pandasを使っているブログ記事などで頻繁に目にします。
DataFrameでは行のラベル(index)と列のラベル(columns)を設定することができます。
10月7日の終値に加えて始値の情報も持ったDataFrameの例が次の画像になります。
左側の縦に並んでいるラベル(=行ラベル)がindex、上側の横に並んでいるラベル(=列ラベル)がcolumnsで設定できるラベルです。
このようなDataFrameを定義する方法は山ほどあるのですが、ここでは2つだけ紹介します。どちらの方法で定義しても上に示したDataFrameが作られます。
# Seriesの辞書から df = pd.DataFrame({ 'open': pd.Series([16883.119141, 2164.189941, 10549.69043], index=['N225', 'GSPC', 'GDAXI']), 'close': pd.Series([16860.089844, 2153.73999, 10490.860352], index=['N225', 'GSPC', 'GDAXI']) }) # 配列の辞書から df = pd.DataFrame({ 'open': [16883.119141, 2164.189941, 10549.69043], 'close': [16860.089844, 2153.73999, 10490.860352] }, index=['N225', 'GSPC', 'GDAXI'])
実際にはCSVなどのデータを読み込んでDataFrameとして扱うことが多いかもしれません。
その場合はread_csvという関数を使用します。
まずはopenclose.csvという名前の次のようなCSVがあるとします。
name,close,open N225,16860.089844,16883.119141 GSPC,2153.739990,2164.189941 GDAXI,10490.860352,10549.690430
このとき、この1行でCSVを読み込んでDataFrameに変換できます。
df = pd.read_csv('./openclose.csv', index_col='name', header=0)
index_colで行ラベルとして使う列を、headerで列ラベルとして使う行番号をそれぞれ指定しています。headerはデフォルトで0となるので、省略しても構いません。
列の選択、追加、削除
特定の列だけを処理したい場合は、次のように抜き出します。
df['close']
name N225 16860.089844 GSPC 2153.739990 GDAXI 10490.860352 Name: close, dtype: float64
列の名前がPythonの変数名として有効なものであれば、メンバ変数のようにアクセスすることもできます。
df.close
列の追加もできます。たとえば、10/7の値動きdelta(=終値 - 始値)の列を追加したい場合は、次のようにして追加できます。
df['delta'] = df['close'] - df['open']
私個人はあまり使ったことはないですが、列の削除はpopでできるみたいです。
df.pop('delta')
assign関数で新しい列を追加する
先ほどの値動きの列deltaは、assignという関数を使っても追加することができます。
df.assign(delta=df['close']-df['open'])
df.assign()は戻り値に列の追加された新しいDataFrameを返しますが、元のdfには変更を加えません。
このassign関数の優れているところは、関数も渡せるところです。たとえば、
df.assign(updown=lambda x: ["UP" if y > 0 else "DOWN" for y in x['close'] - x['open']])
としてやると、deltaがプラスならUP、マイナスならDOWNという文字列を持つupdownという列を新しく追加できます。
要素の選択
こちらの表をそのまま引用します。
操作 | 文法 | 戻り値 |
---|---|---|
列の選択 | df[col] | Series |
行をラベルで選択 | df.loc[label] | Series |
行を整数値で選択 | df.iloc[loc] | Series |
行のスライス | df[5:10] | DataFrame |
行をboolの配列で選択 | df[bool_vec] | DataFrame |
下記の状態のDataFrameを例にして、一つずつ見ていきます。
列の選択
始値(open)の列を取り出してみます。
df['open']
name N225 16883.119141 GSPC 2164.189941 GDAXI 10549.690430 Name: open, dtype: float64
確かに戻り値はSeriesになっています。
行をラベルで選択
日経平均(=N225)の行だけを取り出してみます。行を選択するのに使うlocはlabel-locationに由来しているようです。
df.loc['N225']
close 16860.089844 open 16883.119141 delta -23.029297 Name: N225, dtype: float64
こちらも結果がSeriesで得られました。
行を整数値で選択
次は0スタートで1番目の株価指数を取り出します。使用するilocは、integer-locationの略みたいです。
df.iloc[1]
close 2153.739990 open 2164.189941 delta -10.449951 Name: GSPC, dtype: float64
こちらもS&P500(=GSPC)のデータがSeriesで取り出せました。
行のスライス
Pythonのリストと同様に、スライスを使って行を取り出すこともできます。例えば
df[1:]
とすると、1番目のGSPC以降の行がDataFrameとして取り出せます。
行をbool配列で選択
0番目と2番目の行を取り出したい場合は、例えば[True, False, True]という配列を次のように渡してあげます。
df[[True, False, True]]
コンソールに出力
今まではJupyter Notebookでの出力画面のスクショを紹介していましたが、printやto_string()などの関数を使ってきれいにコンソールに出力することもできます。
print(df)
df.to_string()
print関数での出力結果はこんな形。
close open delta name N225 16860.089844 16883.119141 -23.029297 GSPC 2153.739990 2164.189941 -10.449951 GDAXI 10490.860352 10549.690430 -58.830078
Panel: 3次元のデータ
pandasの名前の由来はpanel dataだった!
実はpandasでは3次元を扱うデータ構造も提供しています。それがPanelです。ちなみに、このPanelというデータ構造(= panel data)がpandasの名前の由来にもなっているようです*1。
The term panel data is derived from econometrics and is partially responsible for the name pandas: pan(el)-da(ta)-s
http://pandas.pydata.org/pandas-docs/stable/dsintro.html#panel
Panelは3次元のデータを扱うので、軸も3つあり、それぞれitems, major_axis, minor_axisと呼ばれるようです。
itemsという軸がDataFrameを持っており、major_axisとminor_axisがそのDataFrameの行(index)と列(columns)に対応します。
Panelの作り方
今まで使用してきた例だと、10月7日の各株価指標の始値・終値をもったDataFrameを扱ってきました。他の日付の始値・終値も扱いたい、となった場合に、Panelが活躍します。
itemsに日付、major_axisに株式指標、minor_axisに始値/終値をとるPanelを使えばいいわけです*2。
# 2日分のDataFrameを用意 df1006 = pd.DataFrame({ 'open': [16913.599609, 2158.219971, 10641.129883], 'close': [16899.099609, 2160.77002, 10568.799805] }, index=['N225', 'GSPC', 'GDAXI']) df1007 = pd.DataFrame({ 'open': [16883.119141, 2164.189941, 10549.69043], 'close': [16860.089844, 2153.73999, 10490.860352] }, index=['N225', 'GSPC', 'GDAXI']) # 辞書でDataFrameを渡してPanelを作成 panel = pd.Panel({ '2016-10-06': df1006, '2016-10-07': df1007 })
panelは3次元なので、printしても簡単に中を見れたりはしません。
<class 'pandas.core.panel.Panel'> Dimensions: 2 (items) x 3 (major_axis) x 2 (minor_axis) Items axis: 2016-10-06 to 2016-10-07 Major_axis axis: N225 to GDAXI Minor_axis axis: close to open
他にも、3次元配列から初期化したりもできます。
要素の操作
Panelの操作はDataFrameによく似ています。まず、このようにitemsを指定してDataFrameを取り出せます。
panel['2016-10-06']
DataFrameを行列のように見立てて、行列の計算なんかもできます。
panel['delta'] = panel['2016-10-07'] - panel['2016-10-06']
要素の選択
先ほど紹介した、panel[item]という形で取り出したDataFrameは、items軸に基づいて取り出したDataFrameでした。
major_axisやminor_axisに基づいてDataFrameを取り出したい場合は、それぞれ次のようにします。
major_axis
panel.major_xs('N225')
minor_axis
panel.minor_xs('close')
欲しいDataFrameが行と列が逆のものの場合は、.Tで転置を取って調節してください。
panel.major_xs('N225').T
DataFrameに変換
to_frame()関数を使うと、PanelをDataFrameに変換することもできます。
panel.to_frame()
関連記事
pandasでデータを操作する際に便利な環境であるJupyter Notebookについて紹介しています。
www.madopro.net