2014/01/26からのアクセス回数 4953 ここで紹介した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を使ってみる †manningのMEAP(プレリリース)からデータサイエンティスト育成本(Practical Data Science with R) がでていますが、これをSageを使って試してみようと思い、RのDataFrameのpython版を探していたら、 ggplotで使われているpandasの存在を知りました。 pandasを一言で表現するとRのDataFrameとRDBのSQLを一つにしたような物です。 pandasの基礎 †最初に必要なライブラリーをimportします。 sageへの入力: import numpy as np import pandas as pd from ggplot import * DataFrame †pandasには、たくさんの機能がありますが、DataFrameの基本的な使いかたを簡単にまとめてみます。 DataFrameの作成には、DataFrame関数に列をキーとするマップを引数とします。 sageへの入力: df = pd.DataFrame({ 'A': [4, 3, 1, 2], 'B': ['foo', 'bar', 'foo', 'bar'], 'C': [True, True, False, False]}) df sageからの出力: 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への入力: df.info() sageからの出力: <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への入力: print df['B'] print df.B sageからの出力: 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を使うのが便利です。 以下の例を出力してみます。
sageへの入力: print df.ix[0] print df.ix[0, 'A'] print df.ix[0:2, 'B':'C'] sageからの出力: 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への入力: print df[ df.A > 1] sageからの出力: A B C 0 4 foo True 1 3 bar True 3 2 bar False [3 rows x 3 columns] また列を指定してのソートも簡単です sageへの入力: df.sort('A') sageからの出力: 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への入力: html.table(df.values.tolist(), header=df.columns.tolist()) sageからの出力: Aggregatin plotting time seriesをsageで試す †DataFrameの基本が何となく分かったところで、ggplotの作者yhat氏の Aggregating & plotting time series in python をSageで試してみます。 使用するデータは、ggplotに付属のアメリカ合衆国の肉のデータ(meat)です。 meatにどのようなデータが入っているのかinfo関数でみてみましょう。日付に続いて肉の種類と出荷量?が入っています。 sageへの入力: meat.info() sageからの出力: <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) データの加工 †infoの結果、broilers, other_chicken, turkeyは、データ数が827ではないため、存在しないレコード(欠損値)が あることが分かりました。 そこで、欠損値のあるデータから閾値を800として、dropna関数を使ってレコードを抽出します。 (dropnaは欠損値処理の関数なので、その例として使っていると思われます。) 残念ながら、sageにインストールしたpandasでは、axis指定がすべての関数で使えません。そこで転置処理(.T)を使って、 代用しました。 meatは時系列データなので、date列をindexにします。 sageへの入力: #meat =meat.dropna(axis=1, thresh=800) meat = meat.T.dropna(thresh=800).T ts = meat.set_index(['date']) データの指定レコードを出力する関数がheadで、終わりはtailです。 sageへの入力: ts.head(10) sageからの出力: 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への入力: ts.tail() sageからの出力: 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] 集計処理 †groupbyとsum関数を使うことで、年毎に集計した結果を簡単に計算することができます。 sageへの入力: ts.groupby(ts.index.year).sum().head(10) sageからの出力: 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への入力: the1940s = ts.groupby(ts.index.year).sum().ix['1940-01-01':'1949-12-31'] sageへの入力: the1940s sageからの出力: 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への入力: def floor_decade(date_value): "Take a date. Returns the decade." return (date_value.year // 10)*10 sageへの入力: pd.to_datetime('2013-10-09') sageからの出力: Timestamp('2013-10-09 00:00:00', tz=None) sageへの入力: floor_decade(_) sageからの出力: 2010 floor_decadeを使って簡単に10年毎の集計を求めることができます。 sageへの入力: ts.groupby(floor_decade).sum() sageからの出力: 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] 図化 †reset_index関数でindexを解除し、値にnameで指定された列名を付けます。 sageへの入力: the1940s.sum().reset_index(name='meat sums in the 1940s') sageからの出力: 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への入力: by_decade=ts.groupby(floor_decade).sum() by_decade.index.name = 'year' by_decade sageからの出力: 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への入力: by_decade=by_decade.reset_index(); by_decade sageからの出力: 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への入力: ggplot(by_decade,aes('year',weight='beef'))+ \ geom_bar()+ \ scale_y_continuous(labels='comma')+ \ ggtitle('Head of Cattle Slaughtered by Decade') sageからの出力: <ggplot: (36185553)> sageへの入力: ggsave('sample1.png', dpi=50) Saving 11.0 x 8.0 in image. melt関数を使ってid_varsでyearをIDとし、列名をvariable列にセットし、値をvalue列にセットした形式に変換します。 sageへの入力: by_decade_long=pd.melt(by_decade,id_vars="year"); by_decade_long.head() 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への入力: ggplot(aes(x='year',weight='value',colour='variable'),data=by_decade_long)+ \ geom_bar()+ \ ggtitle("Meat Production by Decade") sageからの出力: <ggplot: (30542969)> sageへの入力: ggsave('sample2.png', dpi=50) Saving 11.0 x 8.0 in image. 時系列の傾向をみる †今度は、meatデータの時系列での傾向をみてみましょう。 meatデータをロードし直し、geom_lineで時系列でプロットします。 sageへの入力: 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からの出力: <ggplot: (9921013)> sageへの入力: ggsave('sample3.png', dpi=50) Saving 11.0 x 8.0 in image. stat_smoothのスムージング処理で、時系列データの傾向をプロットしてみます。 sageへの入力: ggplot(aes(x='date', y='value', colour='variable'), data=meat_lng) + \ stat_smooth(span=0.10) + \ ggtitle("Smoothed Livestock Production") sageからの出力: <ggplot: (9926157)> sageへの入力: ggsave('sample4.png', dpi=50) Saving 11.0 x 8.0 in image. コメント †皆様のご意見、ご希望をお待ちしております。
Tweet |