Pandas入門講座|13.時系列データの扱い方【PythonのライブラリPandas】

はじめに

この動画では、時系列データ処理について学びます。
時系列データとは、時間を軸に記録されたデータの集まりです。
時系列データの代表的なものには、人口推移のデータや気温や湿度などの気象データ、株価のデータなどがあります。
Pandasでは、データフレームのインデックスを日付型にすることで時系列データとして扱えるようになります。
こうすることで、指定した日数での集計、月末だけの集計、週次や月次の集計などが簡単にできます。
株価などの経済データを好きな期間で分析することもできますし、移動平均や指標となる数値を追加すればさらに深い分析まで可能になります。
このレッスンでは、あるアパレル会社の販売データを用いて説明をします。
準備として、キノコードのサイトに用意しているcsvファイルを2つ、ダウンロードしてください。
そして、学習用のJupyter Labを保存しているフォルダに保存してください。
それではパソコン画面に切り替えてレッスンを進めていきましょう。

準備

import pandas as pd

Pnadasをインポートする記述をします。

pd.options.display.max_rows = 10
pd.options.display.max_columns = None

次に見やすさの観点から、表示する列数、行数を変更しましょう。
pd.options.display.max_rowsで行数を10行に、pd.options.display.max_columnsで列数は無制限に設定します。
実行します。
これで準備ができました。

データの読み込み

df = pd.read_csv('sample.csv', encoding='shift-jis',header=[0])
df

それでは使用するデータを見てみましょう。
ダウンロードいただいた2つのcsvファイルは、アパレル会社の販売データです。
sample.csvは、実績管理表で、社員ごとに何をいくら売り上げたのかがわかります。
もう1つのsample02.csvも同じく実績管理表ですが、異なるのは売上日の入力方法です。
sample.csvの売上日は、このように「/」で区切られています。一方のsample02.csvは、売上日は「年月日」の表記です。
まずはsample.csvファイルを読み込みます。
csvファイルの読み込みには、レッスン6で説明した「read_csvメソッド」を使います。
1行目に項目の行があるので、これをカラム名として読み込めるよう、引数headerに0を指定します。
読み込んだデータを変数dfに代入して、表示してみましょう。実行します。
データを読み込むことができました。
それでは、読み込んだ売上管理表のデータフレームを使って、pandasで時系列データを扱う方法を見ていきましょう。

df.info()

このデータフレームの情報を確認してみましょう。
列に売上日、社員番号などの項目が、行にインデックス番号が付与されています。
インデックスは、RangeIndexです。これは、読み込んだときに自動でできたインデックス番号0123…のことです。
また、データ型は売上日から商品名までがobject、文字列で、単価、数量、売上金額はint64の数値型であることがわかります。
このままでは、これまでのレッスンで見てきたデータフレームと変わりません。
時系列データとして扱うためには、データフレームのインデックスが日時のデータになっている必要があります。
データには、売上日という日付のカラムがあります。
このカラムを、インデックスに変更してみましょう。

時系列データへの変換

df['売上日'] = pd.to_datetime(df['売上日'])
df['売上日'])

まず、売上日の列が文字列になっているので、日時型に変換します。
データ型の変換では、astype関数を使ってきましたが、ここではPandasのto_datetime関数を使います。
to_datetime関数にカラム名の売上日を渡します。表示もしましょう。実行します。
見た目はハイフン表示であまりわかりませんが、データ型がdatetime64[ns]となりました。
datetime64[ns]とは、日時型のひとつで、Pandasで時系列データを扱うのに適したデータ型です。
このように、to_datetime関数で、スラッシュやハイフンを使って日付として入力されたデータはdatetime64[ns]に変換されます。
次に、日時のデータ型になった売上日をインデックスに指定しましょう。

df_2 = df.set_index('売上日')
df_2

すでにあるカラムをインデックスに指定するには、set_index関数を使います。
df.set_index、丸括弧の中にインデックスにしたいカラム名を渡します。これを変数df_2に代入します。
実行します。インデックスが売上日になりました。

df_2.info()

では、変更したデータフレームの情報を見てみましょう。
このように、インデックスがDatetimeIndexに変わりました。
これで時系列データを扱う準備ができました。

df02 = pd.read_csv('sample02.csv', encoding='shift-jis',header=[0])
df02

次に、sample02.csvも読み込んでみましょう。先ほどと同様、1行目をカラムにして読み込みます。実行します。
このように、売上日は年月日の表記です。

df02.info()

このデータフレームの情報を見てみましょう。

df02['売上日'] = pd.to_datetime(df02['売上日'])

売上日のデータ型は、objectの文字列です。時系列データとして扱うには、先ほどと同様にデータ型を日付の型に変換する必要があります。
to_datetimeで変換してみましょう。
エラーになりました。年月日の表記では変換できません。

df02['売上日'] = pd.to_datetime(df02['売上日'], format='%Y年%m月%d日')
df02['売上日']

このような場合は、formatで日付の形式を記述することで変換できるようになります。実行してみましょう。
年月日の表記でも日時のデータ型に変換できました。
このデータフレームも、売上日をインデックスに指定すれば、時系列データとして扱えるようになります。

df = pd.read_csv('sample.csv', encoding='utf-8', header=0, parse_dates=True,index_col='売上日')
df

ここまで、読み込んだデータフレームから日時カラムをインデックスに指定する方法を説明しました。csvを読み込む時点でもこの設定が可能です。
引数parse_datesにTrueを渡し、引数index_colで列名を指定します。
引数parse_datesは、読み込みと同時に日時の列はto_datetime() で変換する引数です。予めデータがわかっている場合は列名をリストで渡しても変換できます。
実行します。
インデックスが売上日のデータフレームができました。
さて、これで時系列データを扱う準備ができました。

時系列データの抽出

df_2

インデックスが日時のデータになっているdf_2で、データの抽出をしてみましょう。

df_2['2020-08']

試しに8月のデータのみを抽出してみましょう。年月を指定するには、シングルクォーテーションで括ります。日まで書く必要がありません。
これで8月分のデータのみ取得できます。実行します。抽出できているようです。

df_2['2020-08-15':'2020-09-14']

では、8月15日〜9月14日までを抽出してみましょう。
スライスを使うことで、開始時点と終了時点の間のデータを抽出することもできます。実行します。
これで、8月15日〜9月14日までのデータが抽出できました。

時系列データの集計

df_3 = df['売上金額']

次は期間ごとの集計方法を見ていきましょう。
時系列データにすると、月ごとの集計や四半期ごとなどの期間の集計が簡単にできます。
それでは、結果がわかりやすいように、売上日と売上金額だけのデータフレームを作成します。このデータフレームで集計してみましょう。

df_3.resample('M')

期間ごとの集約には、resampleメソッドを使います。
そして丸括弧の中に、集計したい期間を指定します。月ごとにしてみましょう。頻度コードのMを記述します。実行します。
各期間で集約されているように見えるものの、ただのオブジェクトになっているだけでデータフレームは表示されません。

df_3.resample('M').sum()
df_3.resample('Q').sum()
df_3.resample('10D').sum()

これを集計するにはresampleメソッドと、sumやmeanなどの集計のメソッドを組み合わせて使います。
月ごとの他に、Qで四半期ごと、10Dで10日ごとでも集計してみましょう。
それぞれにドットsum()とすることで、この期間での合計を算出することができます。実行します。
それぞれ、月ごと、四半期ごと、10日ごとで合計が算出されました。
ここで表示される日付は、指定した期間ごとの最後の日付です。

df_3.resample('M').mean()
df_3.resample('M').max()
df_3.resample('M').min()

同じように、月ごとの平均や最大、最小値を算出してみましょう。
平均はmean、最大はmax、最小はminです。実行します。
各算出値が出力されました。

df_3.resample('Q').agg(['sum', 'mean', 'max', 'min'])

さらに、agg関数を使うと、これらの集計結果を同時に表示できます。
agg関数に算出したい集計メソッドを文字列のリストにして渡します。
四半期ごとの、合計、平均、最大、最小を表示してみましょう。実行します。
同時に表示できました。

曜日ごとの集計

df_3.index.weekday

次は曜日ごとの抽出と集計方法を見ていきましょう。
インデックスがdatetime64[ns]型になっているので、インデックスのweekdayを参照することで、曜日を0〜6の数値で取得できます。
実行します。

Int64Index([5, 6, 0, 1, 3, 4, 5, 5, 5, 3,
...
0, 1, 1, 4, 5, 5, 0, 2, 2, 3],
dtype='int64', name='売上日', length=200)

0が月曜日で、6が日曜日です。各日付の曜日番号が表示されています。

df_3[df_3.index.weekday == 0]

これをDataFrameの抽出条件に使うことで、曜日によるデータ抽出が可能です。
月曜日のデータだけ抽出してみましょう。月曜日は0なので、weekdayが0のデータを抽出します。実行します。
結果が表示されました。

df_3[df_3.index.weekday == 0].mean()

月曜日だけの平均を算出してみましょう。
先ほどのコードに、meanメソッドを組み合わせます。
月曜日の売上金額の平均が算出されました。

df_4 = df_3.set_index(df_3.index.weekday)
df_4.index.name = "曜日番号"
df_4.sum(level="曜日番号").sort_index()

では、少し応用です。特定の曜日だけでなく、各曜日ごとの集計を同時に出力してみましょう。この場合は、曜日の番号をインデックスに設定します。
set_index関数で、df_3の曜日番号をインデックスに変更します。
これだけだと行インデックス名が売上日のままになってしまうので、index.nameで名前を曜日番号にします。
これをsumメソッドで集計します。引数levelにインデックス名の曜日番号を渡すと、曜日ごとの集計ができます。
結果をsort_inndexで見やすくします。実行します。
売上金額(円)
曜日番号
0 1534000
1 1728000
2 1000000
3 1625000
4 1317000
5 763000
6 776000
曜日ごとの売上合計金額が一覧で算出されました。
Pandasで時系列データを扱うことの便利さを知っていただけたでしょうか?
時系列の特色をいかして、他の集計と合わせると、できることの幅が広がります。
キノコードではPandas入門コースの他に、仕事に活かせるPythonの自動化のレッスン、株のデータ分析のレッスンをアップしています。
また人工知能のレッスンや、Pythonでのグラフの作り方についてのレッスンをアップしていく予定です。
新着通知もいくのでぜひチャンネル登録をお願いします。

レッスンで使ったファイルはこちら

■保存方法
Mac:右クリック⇒「リンク先を別名で保存」
Windows:右クリック⇒「名前を付けてリンク先を保存」

Jupyter Labのファイルはこちら

sample.csvファイルはこちら

sample02.csvファイルはこちら