Python でデータ分析をするためのライブラリといえば「Pandas」がデファクトですが、今回は、Pandas の DataFrame の基本的な使い方をまとめてみようと思い立ちました。
特に、DataFrame で時系列データを扱うことを想定しています。具体的には、「金融データのPythonでの扱い方 - 今日も窓辺でプログラム」のように株価データを扱ってみたいと考えています。
前提条件
ローカルの実行環境は以下の通りです。
- MacOS Sierra 10.12.3
- Python 2.7.12 (Anaconda 4.2.0)
- Jupyter Notebook 4.2.0
- pandas 0.18.1
参考までに、MacOS Sierra に(Pandas や Jupyter Notebook などのデータ分析関連の Python パッケージが全部入った)Anaconda を Pyenv を使ってインストールする手順はこちらになります。
<過去記事>
akiyoko.hatenablog.jp
pandas.DataFrame の作成方法
pandas.DataFrame の作成方法は、大きく分けて3つあります。
1)二次元配列を引数にする
二次元配列の一次元目は縦方向、二次元目は横方向に並びます。
import pandas as pd df = pd.DataFrame([[1, 11, 111], [2, 22, 222], [3, 33, 333], [4, 44, 444]]) df
横方向のデータを縦に繋いだイメージです。伝わりますかね??
DataFrame を縦方向に連結する
DataFrame を縦方向に連結するには、pandas.concat() あるいは pandas.DataFrame.append() を使います。
df = pd.DataFrame([[1, 11, 111]]) df2 = pd.DataFrame([[2, 22, 222]]) df3 = pd.DataFrame([[3, 33, 333]]) df4 = pd.DataFrame([[4, 44, 444]]) df = pd.concat([df, df2, df3, df4]) # append でもOK # df = df.append(df2).append(df3).append(df4) df
しかしながら、append は内部的に全体のコピーが毎回走るのでループで一行ずつ追加するような処理は避けた方がよいそうです。
(参考)Python pandas 図でみる データ連結 / 結合処理 - StatsFragments
index や columns を指定する
index(縦方向のラベル) や columns(横方向のラベル)を指定することが可能です。
df = pd.DataFrame([[1, 11, 111], [2, 22, 222], [3, 33, 333], [4, 44, 444]], index=['one', 'two', 'three', 'four'], columns=['A', 'B', 'C']) df
時系列データを扱う
時系列っぽいデータを作成してみます。
df = pd.DataFrame([[18818.580078, 136000, 18450.980469], [18398.759766, 128300, 18374.00], [18410.570312, 142200, 18191.320312], [18139.769531, 163000, 17767.339844]], index=pd.to_datetime(['2016-01-04', '2016-01-05', '2016-01-06', '2016-01-07']), columns=['Open', 'Volume', 'Adj Close']) df
2)辞書を引数にする
辞書を引数にして pandas.DataFrame を作成することもできます。
なお辞書の値は、リストまたは pandas.Series を指定します。
df = pd.DataFrame({'A': [1, 11, 111], 'B': pd.Series([2, 22, 222]), 'C': pd.Series({0: 3, 1: 33, 2: 333})}) df
1)とは逆に、縦方向のデータを横に繋いだイメージになります。
columns の値が辞書ごとに指定できるので便利ですが、時系列データを扱うことを考えると、カラムごとの値のリストをそれぞれ用意する必要があるのでちょっと使いづらいですかね。。
ちなみに、リストの要素数が他と合わないと ValueError が発生してしまいます。
df = pd.DataFrame({'A': [1, 11], 'B': pd.Series([2, 22, 222]), 'C': pd.Series({0: 3, 1: 33, 2: 333})})
ValueError: array length 2 does not match index length 3
なお Series の場合は、足りない要素が「NaN」で補完されるので便利です。
df = pd.DataFrame({'A': [1, 11, 111], 'B': pd.Series([2, 22]), 'C': pd.Series({0: 3, 1: 33, 2: 333})}) df
DataFrame を横方向に連結する
なお、DataFrameを横方向に結合するには、pandas.concat() あるいは pandas.DataFrame.join() を使います。
df = pd.DataFrame({'A': [1, 11, 111]}) df2 = pd.DataFrame({'B': [2, 22, 222]}) # 横方向に結合するときは axis=1 を指定 df = pd.concat([df, df2], axis=1) # あるいは、index が同じであれば、index をキーにして結合する DataFrame.join を使ってもよい # df = df.join(df2) df
時系列データを扱う
2)の作成方法では時系列データを扱いづらいのですが、もしやるなら一旦以下のように DataFrame を作成して、作成した後に DataFrame.T で縦横を反転させる方がいいのかな。
df = pd.DataFrame({'2016-01-04': [18818.580078, 136000, 18450.980469], '2016-01-05': [18398.759766, 128300, 18374.00], '2016-01-06': [18410.570312, 142200, 18191.320312], '2016-01-07': [18139.769531, 163000, 17767.339844]}, index=['Open', 'Volume', 'Adj Close']) df = df.T df
うーん。やっぱり使いづらいですね。。
3)pandas.read_csv を使う
ここからが本題。
pandas.read_csv() を使えば、CSVファイルから簡単に DataFrame を作成することができます。
日経平均のデータ(n225.csv)を読み込んでみます。データは Nikkei 225 Stock - Yahoo Finance からダウンロードしました。
df = pd.read_csv('n225.csv', index_col='Date', parse_dates=True, usecols=['Date', 'Open', 'Volume', 'Adj Close']) df = df.sort_index() df.head(10)
「金融データのPythonでの扱い方 - 今日も窓辺でプログラム」では、以下のように DataFrame を作成していました。
# 2016年1年分の DataFrame を用意 df = pd.DataFrame(index=pd.date_range('2016-01-01', '2016-12-31')) # 日経平均のデータを読み込んで join df = df.join(pd.read_csv('n225.csv', index_col='Date', parse_dates=True, usecols=['Date', 'Open', 'Volume', 'Adj Close'])) # 市場が休みの日のデータを取り除く df = df.dropna() df.head(10)
最初のやり方と結果が変わらないような気がするのですが、まあそれは追々考えることにしましょう。
余談:Iris のデータを Pandas で使う方法
統計分析の練習用サンプルデータと言ったらやっぱり Iris でしょ、ということでデータをロードしようと思ったのですが、pandas には標準で入っていないようです。
Anaconda には標準で scikit-learn が入っているので、そちらを使えば簡単にロードできるようです。
(参考)irisのデータセットをpandasで使う - DISTRICT 37
import pandas as pd from sklearn import datasets iris = datasets.load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) df['Species'] = iris.target_names[iris.target] df.rename(columns={'sepal length (cm)': 'Sepal.Length', 'sepal width (cm)': 'Sepal.Width', 'petal length (cm)': 'Petal.Length', 'petal width (cm)': 'Petal.Width'}, inplace=True) df.head()
なお、rpy2(R interface)パッケージを使ってもいいようですが、rpy2 は Anaconda 4.2.0 にはデフォルトで入っていなかったので見送りました。
(参考)Sample Datasets in Pandas - Stack Overflow
import pandas.rpy.common as rcom iris = rcom.load_data('iris')
ImportError: No module named rpy2.robjects.packages
まとめ
pandas.DataFrame で時系列データを作成するには、pandas.read_csv を使うのが圧倒的に便利です。もちろん、対象データが CSV形式で保存されているなら、という条件付きですが。
pandas.read_csv には把握するのが大変なほど多種多様なオプション引数が用意されており、使いこなせれば強力な武器になりそうです。
(pandas.read_csv — pandas 0.21.1 documentation より)
なお今回のソースコードは、GitHub のリポジトリにアップしておきました。
参考
Pandas について本格的に勉強するならこちらの本を。
Jypyter Notebook の勉強をするならこの本を。
その他、Pandas については以下を参考に。
日付の取り扱いについては以下を参考に。