[[FrontPage]]

#contents

2014/01/26からのアクセス回数 &counter;

ここで紹介したSageワークシートは、以下のURLからダウンロードできます。

http://www15191ue.sakura.ne.jp:8000/home/pub/35/

また、Sageのサーバを公開しているサイト(http://www.sagenb.org/, http://www15191ue.sakura.ne.jp:8000/)にユーザIDを作成することで、ダウンロードしたワークシートを
アップロードし、実行したり、変更していろいろ動きを試すことができます。

* Sageでpandasを使ってみる [#ybd5c844]

manningのMEAP(プレリリース)からデータサイエンティスト育成本(Practical Data Science with R)
がでていますが、これをSageを使って試してみようと思い、RのDataFrameのpython版を探していたら、
ggplotで使われているpandasの存在を知りました。

pandasを一言で表現するとRのDataFrameとRDBのSQLを一つにしたような物です。


** pandasの基礎 [#v8975d44]

最初に必要なライブラリーをimportします。


sageへの入力:
#pre{{
import numpy as np
import pandas as pd
from ggplot import *
}}


*** DataFrame [#x40e0959]

pandasには、たくさんの機能がありますが、DataFrameの基本的な使いかたを簡単にまとめてみます。

DataFrameの作成には、DataFrame関数に列をキーとするマップを引数とします。


sageへの入力:
#pre{{
df = pd.DataFrame({ 'A': [4, 3, 1, 2], 'B': ['foo', 'bar', 'foo', 'bar'], 'C': [True, True, False, False]})
df
}}
sageからの出力:
#pre{{
   A    B      C
0  4  foo   True
1  3  bar   True
2  1  foo  False
3  2  bar  False

[4 rows x 3 columns]
}}


作成されたDataFrameの情報は、info関数で得ることができます。(もっと詳しい情報は、describe関数を使って得ることができます)


sageへの入力:
#pre{{
df.info()
}}
sageからの出力:
#pre{{
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4 entries, 0 to 3
Data columns (total 3 columns):
A    4  non-null values
B    4  non-null values
C    4  non-null values
dtypes: bool(1), object(2)
}}


DataFrameから列を取り出すには、pythonのマップアクセスと同様にキーワード指定(df['B'])
で取り出す方法とドット(.)の後にキーワードを付けて指定(df.B)の2つの方法が使えます。
(Rユーザは、変数名をドットで区切ることが多いので注意が必要です)


sageへの入力:
#pre{{
print df['B']
print df.B
}}
sageからの出力:
#pre{{
0    foo
1    bar
2    foo
3    bar
Name: B, dtype: object
0    foo
1    bar
2    foo
3    bar
Name: B, dtype: object
}}


データフレームの一部を取り出すには、ixを使うのが便利です。
以下の例を出力してみます。

- 0行目を取り出す
- 0行目のA列の要素を取り出す
- 0行から1行のA列からB列(範囲指定では2とCを含まないので注意して下さい)


sageへの入力:
#pre{{
print df.ix[0]
print df.ix[0, 'A']
print df.ix[0:2, 'B':'C']
}}
sageからの出力:
#pre{{
A       4
B     foo
C    True
Name: 0, dtype: object
4
     B      C
0  foo   True
1  bar   True
2  foo  False

[3 rows x 2 columns]
}}


RのDataFrameと同様に条件に抽出もできます。以下の例では、データフレームdfの列Aの値が1より大きいものを抽出しています。


sageへの入力:
#pre{{
print df[ df.A > 1]
}}
sageからの出力:
#pre{{
   A    B      C
0  4  foo   True
1  3  bar   True
3  2  bar  False

[3 rows x 3 columns]
}}


また列を指定してのソートも簡単です

sageへの入力:
#pre{{
df.sort('A')
}}
sageからの出力:
#pre{{
   A    B      C
2  1  foo  False
3  2  bar  False
1  3  bar   True
0  4  foo   True

[4 rows x 3 columns]
}}


Sageでの出力は、タブ表示の関係で列と値の関係が見にくいので、
html.table関数を使って整形する例を示します。


sageへの入力:
#pre{{
html.table(df.values.tolist(), header=df.columns.tolist())
}}
sageからの出力:

&ref(table1.png);

** Aggregatin plotting time seriesをsageで試す [#w28740de]

DataFrameの基本が何となく分かったところで、ggplotの作者yhat氏の
[[Aggregating & plotting time series in python>http://blog.yhathq.com/posts/aggregating-and-plotting-time-series-in-python.html]]
をSageで試してみます。

使用するデータは、ggplotに付属のアメリカ合衆国の肉のデータ(meat)です。		

meatにどのようなデータが入っているのかinfo関数でみてみましょう。日付に続いて肉の種類と出荷量?が入っています。


sageへの入力:
#pre{{
meat.info()
}}
sageからの出力:
#pre{{
<class 'pandas.core.frame.DataFrame'>
Int64Index: 827 entries, 0 to 826
Data columns (total 8 columns):
date               827  non-null values
beef               827  non-null values
veal               827  non-null values
pork               827  non-null values
lamb_and_mutton    827  non-null values
broilers           635  non-null values
other_chicken      143  non-null values
turkey             635  non-null values
dtypes: datetime64[ns](1), float64(7)
}}


*** データの加工 [#sff1875f]

infoの結果、broilers, other_chicken, turkeyは、データ数が827ではないため、存在しないレコード(欠損値)が
あることが分かりました。

そこで、欠損値のあるデータから閾値を800として、dropna関数を使ってレコードを抽出します。
(dropnaは欠損値処理の関数なので、その例として使っていると思われます。)

残念ながら、sageにインストールしたpandasでは、axis指定がすべての関数で使えません。そこで転置処理(.T)を使って、
代用しました。

meatは時系列データなので、date列をindexにします。


sageへの入力:
#pre{{
#meat =meat.dropna(axis=1, thresh=800)
meat = meat.T.dropna(thresh=800).T
ts = meat.set_index(['date'])
}}

データの指定レコードを出力する関数がheadで、終わりはtailです。


sageへの入力:
#pre{{
ts.head(10)
}}
sageからの出力:
#pre{{
           beef veal  pork lamb_and_mutton
date                                      
1944-01-01  751   85  1280              89
1944-02-01  713   77  1169              72
1944-03-01  741   90  1128              75
1944-04-01  650   89   978              66
1944-05-01  681  106  1029              78
1944-06-01  658  125   962              79
1944-07-01  662  142   796              82
1944-08-01  787  175   748              87
1944-09-01  774  182   678              91
1944-10-01  834  215   777             100

[10 rows x 4 columns]
}}


sageへの入力:
#pre{{
ts.tail()
}}
sageからの出力:
#pre{{
              beef  veal    pork lamb_and_mutton
date                                            
2012-07-01  2200.8   9.5  1721.8            12.5
2012-08-01  2367.5  10.1  1997.9            14.2
2012-09-01    2016   8.8    1911            12.5
2012-10-01  2343.7  10.3  2210.4            14.2
2012-11-01  2206.6  10.1  2078.7            12.4

[5 rows x 4 columns]
}}


*** 集計処理 [#b05e4309]

groupbyとsum関数を使うことで、年毎に集計した結果を簡単に計算することができます。


sageへの入力:
#pre{{
ts.groupby(ts.index.year).sum().head(10)
}}
sageからの出力:
#pre{{
       beef  veal   pork  lamb_and_mutton
1944   8801  1629  11502             1001
1945   9936  1552   8843             1030
1946   9010  1329   9220              946
1947  10096  1493   8811              779
1948   8766  1323   8486              728
1949   9142  1240   8875              587
1950   9248  1137   9397              581
1951   8549   972  10190              508
1952   9337  1080  10321              635
1953  12055  1451   8971              715

[10 rows x 4 columns]
}}


また集計された結果もDataFrameなので、ix関数を使って絞り込むことができます。

以下の例では、1940年代のデータのみをthe1940sにセットしています。


sageへの入力:
#pre{{
the1940s = ts.groupby(ts.index.year).sum().ix['1940-01-01':'1949-12-31']
}}

sageへの入力:
#pre{{
the1940s
}}
sageからの出力:
#pre{{
       beef  veal   pork  lamb_and_mutton
1944   8801  1629  11502             1001
1945   9936  1552   8843             1030
1946   9010  1329   9220              946
1947  10096  1493   8811              779
1948   8766  1323   8486              728
1949   9142  1240   8875              587

[6 rows x 4 columns]
}}


ユーザの定義した関数をgroupbyに指定することができます。

次の例では、floor_decade関数を使ってyearから10年単位に切り捨てた年を計算しています。


sageへの入力:
#pre{{
def floor_decade(date_value):
    "Take a date. Returns the decade."
    return (date_value.year // 10)*10
}}

sageへの入力:
#pre{{
pd.to_datetime('2013-10-09')
}}
sageからの出力:
#pre{{
Timestamp('2013-10-09 00:00:00', tz=None)
}}


sageへの入力:
#pre{{
floor_decade(_)
}}
sageからの出力:
#pre{{
2010
}}


floor_decadeを使って簡単に10年毎の集計を求めることができます。

sageへの入力:
#pre{{
ts.groupby(floor_decade).sum()
}}
sageからの出力:
#pre{{
          beef     veal      pork  lamb_and_mutton
1940   55751.0   8566.0   55737.0           5071.0
1950  119161.0  12693.0   98450.0           6724.0
1960  177754.0   8577.0  116587.0           6873.0
1970  228947.0   5713.0  132539.0           4256.0
1980  230100.0   4278.0  150528.0           3394.0
1990  243579.0   2938.0  173519.0           2986.0
2000  260540.7   1685.3  208211.3           1964.7
2010   76391.5    371.9   66491.2            455.6

[8 rows x 4 columns]
}}


*** 図化 [#ofa4b3a2]
reset_index関数でindexを解除し、値にnameで指定された列名を付けます。

sageへの入力:
#pre{{
the1940s.sum().reset_index(name='meat sums in the 1940s')
}}
sageからの出力:
#pre{{
             index  meat sums in the 1940s
0             beef                   55751
1             veal                    8566
2             pork                   55737
3  lamb_and_mutton                    5071

[4 rows x 2 columns]
}}


by_decadeに10年毎の集計結果を入れ、indexの名前をyearとします。

sageへの入力:
#pre{{
by_decade=ts.groupby(floor_decade).sum()
by_decade.index.name = 'year'
by_decade
}}
sageからの出力:
#pre{{
          beef     veal      pork  lamb_and_mutton
year                                              
1940   55751.0   8566.0   55737.0           5071.0
1950  119161.0  12693.0   98450.0           6724.0
1960  177754.0   8577.0  116587.0           6873.0
1970  228947.0   5713.0  132539.0           4256.0
1980  230100.0   4278.0  150528.0           3394.0
1990  243579.0   2938.0  173519.0           2986.0
2000  260540.7   1685.3  208211.3           1964.7
2010   76391.5    371.9   66491.2            455.6

[8 rows x 4 columns]
}}


reset_indexでyearがindexからyear列に変更します。

sageへの入力:
#pre{{
by_decade=by_decade.reset_index(); by_decade
}}
sageからの出力:
#pre{{
   year      beef     veal      pork  lamb_and_mutton
0  1940   55751.0   8566.0   55737.0           5071.0
1  1950  119161.0  12693.0   98450.0           6724.0
2  1960  177754.0   8577.0  116587.0           6873.0
3  1970  228947.0   5713.0  132539.0           4256.0
4  1980  230100.0   4278.0  150528.0           3394.0
5  1990  243579.0   2938.0  173519.0           2986.0
6  2000  260540.7   1685.3  208211.3           1964.7
7  2010   76391.5    371.9   66491.2            455.6

[8 rows x 5 columns]
}}


ggplotを使ってby_decadeのbeefの値を棒グラフに表示します。

sageへの入力:
#pre{{
ggplot(by_decade,aes('year',weight='beef'))+ \
    geom_bar()+ \
    scale_y_continuous(labels='comma')+ \
    ggtitle('Head of Cattle Slaughtered by Decade')
}}
sageからの出力:
#pre{{
<ggplot: (36185553)>
}}


sageへの入力:
#pre{{
ggsave('sample1.png', dpi=50)
}}
#pre{{
Saving 11.0 x 8.0 in image.
}}

&ref(sample1.png);

melt関数を使ってid_varsでyearをIDとし、列名をvariable列にセットし、値をvalue列にセットした形式に変換します。

sageへの入力:
#pre{{
by_decade_long=pd.melt(by_decade,id_vars="year"); by_decade_long.head()
}}
#pre{{
   year variable   value
0  1940     beef   55751
1  1950     beef  119161
2  1960     beef  177754
3  1970     beef  228947
4  1980     beef  230100

[5 rows x 3 columns]
}}


ggplotのaesでweightにvalue, colourにvariableを指定することで、肉の種類別に積み上げられた
棒グラフができました。

sageへの入力:
#pre{{
ggplot(aes(x='year',weight='value',colour='variable'),data=by_decade_long)+ \
    geom_bar()+ \
    ggtitle("Meat Production by Decade")
}}
sageからの出力:
#pre{{
<ggplot: (30542969)>
}}


sageへの入力:
#pre{{
ggsave('sample2.png', dpi=50)
}}
#pre{{
Saving 11.0 x 8.0 in image.
}}

&ref(sample2.png);

*** 時系列の傾向をみる [#ked3f1b1]
今度は、meatデータの時系列での傾向をみてみましょう。

meatデータをロードし直し、geom_lineで時系列でプロットします。
sageへの入力:
#pre{{
from ggplot import meat
meat_lng = pd.melt(meat, id_vars=['date'])
ggplot(aes(x='date', y='value', colour='variable'), data=meat_lng) + geom_line() 
}}
sageからの出力:
#pre{{
<ggplot: (9921013)>
}}


sageへの入力:
#pre{{
ggsave('sample3.png', dpi=50) 
}}
#pre{{
Saving 11.0 x 8.0 in image.
}}

&ref(sample3.png);

stat_smoothのスムージング処理で、時系列データの傾向をプロットしてみます。
sageへの入力:
#pre{{
ggplot(aes(x='date', y='value', colour='variable'), data=meat_lng) + \
    stat_smooth(span=0.10) + \
    ggtitle("Smoothed Livestock Production") 
}}
sageからの出力:
#pre{{
<ggplot: (9926157)>
}}


sageへの入力:
#pre{{
ggsave('sample4.png', dpi=50) 
}}
#pre{{
Saving 11.0 x 8.0 in image.
}}

&ref(sample4.png);

** コメント [#e5830c21]
#vote(おもしろかった[4],そうでもない[0],わかりずらい[0])
#vote(おもしろかった[5],そうでもない[0],わかりずらい[0])

皆様のご意見、ご希望をお待ちしております。
- pandas のインストール方法を載せていただくと助かります。よろしくお願いします。 -- [[ysato]] &new{2014-10-07 (火) 19:09:13};

#comment_kcaptcha

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc