🐍

【Python】Shift()を使って日付データログそれぞれの時間差を取得する

2024/12/07に公開

やりたいこと

想定のユースケースとしては、ビジネスの状況を分析するときに、以下のようにアクティブ度合いやライフサイクルによる分類を設けて、それぞれのメカニズムの違いを確認し、それぞれに最適化した施策を検討するようなシーンがあると思います。

  • 新規ユーザー
  • 継続ユーザー
  • 休眠ユーザー
  • 復帰ユーザー

新規、継続、休眠については定義がシンプルなことが多いですが、仮に復帰については定義を「最後のログインから30日以上ぶりのログインとする」とした場合、ログイン履歴から「そのログインは、最後のログインから何日ぶりのログインなのか?」をユーザー1人1人に対して演算する必要があります。

今回はこのような演算をログイン履歴から簡単に実現するやり方のメモを残します。

実際にやってみる

まずは基本ライブラリをimportします。

import numpy as np
import pandas as pd
import datetime

説明用に、ユーザーのログイン履歴のDataframeを作成します。

df = pd.DataFrame(
    {
        'user_id': [100, 101, 107, 110, 100, 105, 101, 107, 110],
        'login_timestamp': ['2024-08-01 21:00:23', '2024-08-02 23:03:44', '2024-08-05 12:15:00', '2024-08-05 13:04:55', '2024-08-10 13:10:22', '2024-08-16 16:10:12', '2024-08-22 14:11:34', '2024-09-07 23:09:10', '2024-08-29 09:25:44']
    })

dfを呼び出すと、こんなdataframeが確認できます。

あとでlogin_timestampを演算に使いたいわけですが、辞書型の文字列で作成しているため、このままでは演算できません。
これをto_datetime()関数を使って日付データであるdatetime64型に変換します。

# stringを日付データに変更する
df['login_timestamp'] = pd.to_datetime(df['login_timestamp'])

この処理のBefore/Afterでデータの型を確認してみると安心します。


Before


After

次に、sort_values()を使って、user_idごとに、login_timestampを降順に整理します。

df = df.sort_values(by=['user_id', 'login_timestamp'], ascending=False)


上記処理のあと、呼び出したdfの中身

次に、shift()を使って、login_timestampの1つ前のログインをprevious_login_timestampと定義して、user_idごとにカラム付与します。

df['previous_login_timestamp'] = df.groupby('user_id')['login_timestamp'].shift(-1)

直感的にわかりにくい場合は、dfを呼び出してみるとわかります。
下のキャプチャのように、例えばuser_id : 110のユーザーは、最新のログインが2024-08-29 09:25:44で、その直前のログインが2024-08-05 13:04:55なので、それがそのままprevious_login_timestampとしてカラム化できています。

それより直前のログイン履歴はないので、2024-08-05 13:04:55に対するprevious_login_timestampは、ちゃんとNat(Not a Time)になってくれています。

下準備ができたので、演算に入ります。
login_timestampとprevious_login_timestampの差分をlogin_diffと定義し、以下のようにシンプルに計算します。

df['login_diff'] = df['login_timestamp'] - df['previous_login_timestamp']

演算結果は以下のようになります。

23 days 20:20:49のように、細かすぎるので、xx daysのようにシンプルな形に落とし込みたいです。

# x daysという形のカラムになっているので、x の部分だけ抽出する
df['login_diff_days'] = df['login_diff'].dt.days


上記の実行結果

これにて、各ユーザーの各ログイン履歴ごとに、直前のログインから次のログインまでの経過日数を演算することができました。

これをどう料理するかは、ユースケース次第ですが、私の場合はこの経過日数が30以上のとき、復帰ユーザーのフラグを付与したいことがあるので、参考までにその処理を記載しておきます。

df['reactivated_user_flg'] = df['login_diff_days'].apply(lambda x: 1 if x >= 30 else 0)


上記の実行結果

Discussion