akiyoko blog

akiyoko の IT技術系ブログです

Pandas の DataFrame の基本的な使い方

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

横方向のデータを縦に繋いだイメージです。伝わりますかね??

f:id:akiyoko:20170325004558p:plain:w100


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

f:id:akiyoko:20170325005953p:plain:w100

しかしながら、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

f:id:akiyoko:20170325010057p:plain:w120


時系列データを扱う

時系列っぽいデータを作成してみます。

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

f:id:akiyoko:20170325010155p:plain:w300


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)とは逆に、縦方向のデータを横に繋いだイメージになります。

f:id:akiyoko:20170325010246p:plain:w120

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

f:id:akiyoko:20170325110441p:plain:w120

 

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

f:id:akiyoko:20170325010345p:plain:w80


 

時系列データを扱う

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

f:id:akiyoko:20170325010408p:plain:w300


うーん。やっぱり使いづらいですね。。



 

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)

f:id:akiyoko:20170326012255p:plain:w300


金融データの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)

f:id:akiyoko:20170326012353p:plain:w300


最初のやり方と結果が変わらないような気がするのですが、まあそれは追々考えることにしましょう。



 

余談: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()

f:id:akiyoko:20170331230004p:plain:w450




なお、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 には把握するのが大変なほど多種多様なオプション引数が用意されており、使いこなせれば強力な武器になりそうです。

f:id:akiyoko:20170325121734p:plain

pandas.read_csv — pandas 0.21.1 documentation より)


なお今回のソースコードは、GitHub のリポジトリにアップしておきました。

github.com