LoginSignup
10
14

More than 5 years have passed since last update.

pandasを使ってイベントデータを1ユーザ1行の形式に集計する

Posted at

はじめに

今回「イベントデータ」という言葉を (時刻, イベント名 (, ユーザ)(, 数量)) のようなデータ の意味で使います。
ユーザの予測モデルなどを作ろうとした時に、このようなイベントデータを「1ユーザ1行」になるように整形したくなることがあります。

pandas でこの辺を処理を行う方法についてメモしておきます。

方法

まず、下記のようなイベントデータを例に考えます。

import pandas as pd

data = [
    ['user1', '2015-7-1 10:00:00', 'login'],
    ['user1', '2015-7-1 10:00:10', 'item'],
    ['user1', '2015-7-1 10:00:30', 'item'],
    ['user2', '2015-7-1 10:01:00', 'top'],
    ['user1', '2015-7-1 10:01:30', 'cart'],
    ['user2', '2015-7-1 10:01:50', 'login'],
    ['user2', '2015-7-1 10:02:30', 'logout'],

    ['user1', '2015-7-2 13:00:00', 'login'],
    ['user1', '2015-7-2 13:01:00', 'logout'],
    ['user3', '2015-7-2 13:01:00', 'top'],
    ['user2', '2015-7-2 13:01:50', 'login'],
    ['user2', '2015-7-2 13:02:30', 'item'],
    ['user2', '2015-7-2 13:03:30', 'cart'],
    ['user2', '2015-7-2 13:03:30', 'history'],
]
df = pd.DataFrame(data)
df.columns = ['user_id', 'time', 'event']
df['time'] = pd.to_datetime(df['time'])
df['dummy'] = 1
df
user_id time event dummy
0 user1 2015-07-01 10:00:00 login 1
1 user1 2015-07-01 10:00:10 item 1
2 user1 2015-07-01 10:00:30 item 1
3 user2 2015-07-01 10:01:00 top 1
4 user1 2015-07-01 10:01:30 cart 1
5 user2 2015-07-01 10:01:50 login 1
6 user2 2015-07-01 10:02:30 logout 1
7 user1 2015-07-02 13:00:00 login 1
8 user1 2015-07-02 13:01:00 logout 1
9 user3 2015-07-02 13:01:00 top 1
10 user2 2015-07-02 13:01:50 login 1
11 user2 2015-07-02 13:02:30 item 1
12 user2 2015-07-02 13:03:30 cart 1
13 user2 2015-07-02 13:03:30 history 1

このデータを 「1ユーザ1行」として「日毎イベント毎の発生回数の総和」を列とするように整形したいとします。

pivot_table と Grouper

DataFrameクラスの pivot_table() を使うと Excelのピボットテーブルと似たような操作を行うことができます。
日毎に集計したいのですが、 Grouper() というのを使うとdatetime型の列に対してよしなにGroup化できます。なんて便利な・・。

res2 = df.pivot_table(index=['user_id', pd.Grouper(freq='d', key='time')], columns='event', values='dummy', aggfunc=len)
res2
event cart history item login logout top
user_id time
user1 2015-07-01 1 NaN 2 1 NaN NaN
2015-07-02 NaN NaN NaN 1 1 NaN
user2 2015-07-01 NaN NaN NaN 1 1 1
2015-07-02 1 1 1 1 NaN NaN
user3 2015-07-02 NaN NaN NaN NaN NaN 1

Grouperの freq='d' なので1日単位での集計になります。 freq='M' とかにすると月単位などになります。

日付を列にもってくる

unstack() を使うと良いです。

res3 = res2.unstack()
res3
event cart history item login logout top
time 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02
user_id
user1 1 NaN NaN NaN 2 NaN 1 1 NaN 1 NaN NaN
user2 NaN 1 NaN 1 NaN 1 1 1 1 NaN 1 NaN
user3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1

日付を上にもってきたい

swaplevel(入れ替えたいIndex1, 入れ替えたいIndex2) を使います。
あと、列(軸番号1)について操作したいので axis=1 を付けます。

res4 = res3.swaplevel(0, 1, axis=1)
res4
time 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02 2015-07-01 2015-07-02
event cart cart history history item item login login logout logout top top
user_id
user1 1 NaN NaN NaN 2 NaN 1 1 NaN 1 NaN NaN
user2 NaN 1 NaN 1 NaN 1 1 1 1 NaN 1 NaN
user3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1

列は日付順にならんで欲しい

sortlevel() を使います。

res4.sortlevel(0, axis=1)
time 2015-07-01 2015-07-02
event cart history item login logout top cart history item login logout top
user_id
user1 1 NaN 2 1 NaN NaN NaN NaN NaN 1 1 NaN
user2 NaN NaN NaN 1 1 1 1 1 1 1 NaN NaN
user3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1

これで目的の形に整形できました。

さいごに

「Eventの種類数×日付数」の数の列ができてしまうので、それが多すぎる場合は使えないですね。
Event種類数が多くないか、月単位で集計するという場合には使えると思います。

それにしてもpandas便利ですねー

10
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
14