intellista

engineer's notes about application development, data analysis, and so on

Pandasで次のレコードとの差を計算する方法とは?


こんにちは!

IoTがらみで監視機器のデータや工場設備のデータなどを扱っていると、時刻が記録されたカラムから「時間」を求めたくなるシーンがよくあります。
具体的には、あるレコードと次のレコードの時刻のカラム値の差をとってレコード間の「時間」を求めるのです。

このとき、ループ処理を組んでレコード間の差を求めることもできますが、Pandasならループ処理を組まずシンプルに実装できます。

そこで今回は、「Pandasで次のレコードとの差を計算する」ことについてお話したいです。

背景

Pandasでのデータ加工でよくあるのが「ある列について、次の行との差を計算する」というニーズです。

時系列データの差を取って時間を求めたり、推移する値の差を取って増減の幅を可視化するなど、よくあります。
こういったときは、次のレコードの値との差を取ることになります。

それだけなら単純ですが、ふつうは複数の階層的なID単位に差を求めたいことが多いです。
例えば、工場ごとに商品ごとの製造完了時刻があったとき、工場ごとに商品ごとの製造時間(次行の完了時間-今行の完了時間)を求めたいことがよくあります。

こんな時、プログラミングの経験があればすぐに「forループ回して、中でif文でIDをチェック」と思い浮かぶはずです。

もちろんPandasでもそのようにできますが、お作法としては好ましくありません。
Pandasはなるべくforループを使わない書き方を好みます。

※と言っている私も、実はPandasの開発者の書籍「Pythonによるデータ分析入門 第2版」で勉強して知りました。

このときに役立つのが次の2つのPandasのメソッドです。

  • groupbyメソッド
  • shiftメソッド

この2つを使えば、たったの3行で書けます。

  dfg = df.groupby(['FACTORY','ITEM'])
  df['NEXT_END_TIME'] = dfg['END_TIME'].shift(-1)
  df['DURATION_SECONDS'] = (df['NEXT_END_TIME'] - df['END_TIME']).dt.seconds

ということで、具体例を見てみましょう。

具体例

「ある列について、次の行との差を計算する」ための具体例は次のとおりです。


  • 1つ目のセルは、単なる準備です。
  • 2つ目のセルは、今回の元データとしたサンプルデータです。
  • 3つ目のセルが、今回のポイントです。groupbyメソッドとshiftメソッドで時間を求めています。
    なお、各グループの末尾のレコードの時間はNaNになります。(次のレコードが存在しないので)

ちなみに、これと同じことををループ処理でやろうとすると、かなりゴリゴリと力技でコーディングすることになります。
次のような感じです。

  factory = None
  item = None
  for row in df.itertuples():
    if row.Index is not 0:
      if factory == row.FACTORY and item == row.ITEM:
      ...

これは読みづらいですね。しかも処理速度が遅いです。
せっかく努力しているのですが、残念な例だと思います。
もしこんなコードを現場で見かけたら、中身によってはリファクタリングしたほうがいいかもしれません。

なお、この話に限らないことですが、言語やライブラリの仕様や組み込み関数を把握することは重要です。
把握せずにfor文やif文で強引に大量のコードを書くと、努力がもったいないうえに、そのコードを受け取った人たちも苦労します。
私も含めて今後とも、実装する前に「スマートな方法がないのか?」と気づき確認したいものです。

なお、スマートな方法を把握する効率的な方法は、やはり体系的な理解です。
私はPandasについて、作者の著書を読み込んでいますが、非常に体系的でした。
そのおかげで、Pandasらしい発想ができるようになったと思います。

まとめ

今回は「Pandasで次のレコードとの差を計算する」方法についてお話しました。
Pandasらいしいスマートな書き方で自他ともに時短できると嬉しいです!

なお、Pandasを含め、Pythonには様々なコツが必要なシーンが多々あります。
Python、Pandas、データ分析、に関するコツなどを次の記事にまとめてありますので、是非読んでみてください!
intellista.hatenablog.com