データと情報は似て非なるもの。意味のある情報を取り出すために、データを「使える」状態にするには意外と地道な手続きが必要です。手短に実行するために必要なスキルを紹介していきます。
前回はデータを取り込んだり書き出したりする方法を紹介しましたが、実際の分析対象となるデータのほとんどは、そのまま分析できる状態にはありません。Webログなどはカンマ区切り形式ではなくスペースやカッコで区切られていますので、データを分割する必要があります。また、時系列に関する項目もフォーマットがまちまちなので統一する必要がありますので時系列データのクレンジングについても解説します。では早速具体的な例を使って説明していきたいと思います。
ビジネス上の出来事には時間が付きもので、時間の変化とともにビジネスも大きく変化していきますから、時系列のデータを扱うことはある意味で「必然」と言うことが出来ます。まずは前回も紹介した、データ分析のためのライブラリpandas(pandas: powerful Python data analysis toolkit)を使って時系列(Time Series)データを扱う時に課題となるポイントを説明していきましょう。具体的には、個々のデータごとの時間間隔を合わせたり、足りないデータを補完する機能などを用いていきます。
前回と同様に、電力の使用状況データ(http://www.tepco.co.jp/forecast/html/images/juyo-2013.csv)を取り込みます。本稿ではIPythonなど、本連載で紹介してきた環境を前提に解説を進めます。バックナンバーを参照して環境セットアップしておきましょう(バックナンバー)。
In [1]: # ライブラリのインポート In [2]: import pandas as pd In [3]: import numpy as np In [4]: # CSVデータの取り込み In [5]: df = pd.read_csv('http://www.tepco.co.jp/forecast/html/images/juyo-2013.csv', skiprows=3, names=['date', 'time', 'actual'], encoding='Shift_JIS')
取得したデータは、下記のようなフォーマットになっています。
2013/7/1 18:10 UPDATE DATE,TIME,実績(万kW) 2013/1/1,0:00,2873 2013/1/1,1:00,2716 2013/1/1,2:00,2592 2013/1/1,3:00,2482 2013/1/1,4:00,2412 2013/1/1,5:00,2405 2013/1/1,6:00,2499 :: ::
元のデータでは日付と時刻が別の項目となっています。時系列でデータを処理する際には、日時の経過を追って見ていきたいので、日付と時刻は結合しておいた方が扱いやすくなります。
次に日付と時間を結合して時系列のインデックスを生成し(In [7])、時系列インデックスを持つ電力使用量の1次元データ(Series)を生成します。
In [6]: # 時系列インデックスをもつ1次元データ(Series)の生成 In [7]: idx = pd.to_datetime(df['date']+' '+df['time']) In [8]: ts = pd.Series(df.actual.values, index=idx) In [9]: ts.head(10) Out[9]: 2013-01-01 00:00:00 2873 2013-01-01 01:00:00 2716 2013-01-01 02:00:00 2592 2013-01-01 03:00:00 2482 2013-01-01 04:00:00 2412 2013-01-01 05:00:00 2405 2013-01-01 06:00:00 2499 2013-01-01 07:00:00 2646 2013-01-01 08:00:00 2778 2013-01-01 09:00:00 2773 dtype: int64
Out[9]のように1時間ごとのデータが生成されます。このデータをダウンサンプリングして日次や月次のデータに変換してみましょう。
TimeSeries.resampleメソッドを使用して期間を変更しますが、In [11]では期間に日次(D)を指定してその期間の平均を計算しています。同様にIn [12]では月次の平均値を計算しています。期間の指定については、よく使うものを表1にまとめてありますが詳しくはマニュアルの「Time Series/Date functionality」(リンク)に詳細がありますので参考にしてください。また、howオプションで'max'や'min'、'sum'を指定して最大値や最小値、合計値を計算することもできます。
期間の指定 | 説明 |
---|---|
A | 1年毎(年度末が12月) |
A-MAR | 1年毎(年度末が3月) |
Q | 4半期毎(年度末が12月) |
Q-MAR | 4半期毎(年度末が3月) |
M | 月次 |
W | 週次 |
D | 日次 |
H | 1時間単位 |
T(min) | 1分単位 |
In [10]: # 期間の変更と平均値の計算(ダウンサンプリング) In [11]: ts.resample('D', how='mean', kind='period').head(10) Out[11]: 2013-01-01 2717.625000 2013-01-02 2679.375000 2013-01-03 2871.458333 2013-01-04 3305.041667 2013-01-05 3462.083333 2013-01-06 3341.041667 2013-01-07 3759.375000 2013-01-08 3780.708333 2013-01-09 3769.125000 2013-01-10 3832.833333 Freq: D, dtype: float64 In [12]: ts.resample('M', how='mean', kind='period') Out[12]: 2013-01 3632.861559 2013-02 3674.470238 2013-03 3131.790323 2013-04 2966.729167 2013-05 2870.169355 2013-06 3047.296875 Freq: M, dtype: float64
では次に期間を元のデータよりも短くしてみましょう。In [14]では期間を30分に指定していますのでデータの欠損が発生してしまいますが、fill_methodを用いることで欠損データを補完しています。'ffill'は前のデータの値を使って補完するオプションで、'bfill'(In [15])は後ろのデータを使って補完するものです。また、In [16]のように前後の値を使って線形(このケースでは前後の平均)に補完することもできます。
In [13]: # 期間の変更とデータの補完(アップサンプリング) In [14]: ts.resample('30min', fill_method='ffill').head(10) Out[14]: 2013-01-01 00:00:00 2873 2013-01-01 00:30:00 2873 2013-01-01 01:00:00 2716 2013-01-01 01:30:00 271 2013-01-01 02:00:00 2592 2013-01-01 02:30:00 2592 2013-01-01 03:00:00 2482 2013-01-01 03:30:00 2482 2013-01-01 04:00:00 2412 2013-01-01 04:30:00 2412 Freq: 30T, dtype: int64 In [15]: ts.resample('30min', fill_method='bfill').head(10) Out[15]: 2013-01-01 00:00:00 2873 2013-01-01 00:30:00 2716 2013-01-01 01:00:00 2716 2013-01-01 01:30:00 2592 2013-01-01 02:00:00 2592 2013-01-01 02:30:00 2482 2013-01-01 03:00:00 2482 2013-01-01 03:30:00 2412 2013-01-01 04:00:00 2412 2013-01-01 04:30:00 2405 Freq: 30T, dtype: int64 In [16]: pd.Series.interpolate(ts.resample('30min'), method='linear').head(10) Out[16]: 2013-01-01 00:00:00 2873.0 2013-01-01 00:30:00 2794.5 2013-01-01 01:00:00 2716.0 2013-01-01 01:30:00 2654.0 2013-01-01 02:00:00 2592.0 2013-01-01 02:30:00 2537.0 2013-01-01 03:00:00 2482.0 2013-01-01 03:30:00 2447.0 2013-01-01 04:00:00 2412.0 2013-01-01 04:30:00 2408.5 Freq: 30T, dtype: float64
ここまでは時系列データの期間を短くしたり長くしたりする方法を紹介しました。次ページからは、さらにpandasを使いこなしたデータ加工を試してみます。
Copyright © ITmedia, Inc. All Rights Reserved.