連載
» 2013年07月16日 18時03分 UPDATE

ITエンジニアのためのデータサイエンティスト養成講座(4):ログを分析するには? XMLデータを分析するには? pandasでデータを分析できる状態にする (1/3)

データと情報は似て非なるもの。意味のある情報を取り出すために、データを「使える」状態にするには意外と地道な手続きが必要です。手短に実行するために必要なスキルを紹介していきます。

[中林紀彦,日本アイ・ビー・エム]

backn2.gif

連載バックナンバー

はじめに

 前回はデータを取り込んだり書き出したりする方法を紹介しましたが、実際の分析対象となるデータのほとんどは、そのまま分析できる状態にはありません。Webログなどはカンマ区切り形式ではなくスペースやカッコで区切られていますので、データを分割する必要があります。また、時系列に関する項目もフォーマットがまちまちなので統一する必要がありますので時系列データのクレンジングについても解説します。では早速具体的な例を使って説明していきたいと思います。

ビジネスは時間に追われている!:時系列データを分析する際の課題

 ビジネス上の出来事には時間が付きもので、時間の変化とともにビジネスも大きく変化していきますから、時系列のデータを扱うことはある意味で「必然」と言うことが出来ます。まずは前回も紹介した、データ分析のためのライブラリpandas(pandas: powerful Python data analysis toolkit)を使って時系列(Time Series)データを扱う時に課題となるポイントを説明していきましょう。具体的には、個々のデータごとの時間間隔を合わせたり、足りないデータを補完する機能などを用いていきます。

データをインポートする:pandas.read_csv

 前回と同様に、電力の使用状況データ(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')

日付と時間を結合した上でインデックスを生成する:pandas.to_datetime、pandas.series

 取得したデータは、下記のようなフォーマットになっています。

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

ダウンサンプリングする:pandas.TimeSeries.resample

 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

アップサンプリングする:fill_method

 では次に期間を元のデータよりも短くしてみましょう。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を使いこなしたデータ加工を試してみます。

       1|2|3 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。