実行環境
- Python 3.10.2
- pandas 1.4.1
やりたいこと
以下のデータを、user
ごとに1週間単位(日曜日始まり)の合計のcount
を算出したいです。
user,date,count
alice,2022-03-01,1
alice,2022-03-05,2
alice,2022-03-06,3
alice,2022-03-07,4
alice,2022-03-12,5
alice,2022-03-13,6
alice,2022-03-14,7
bob,2022-03-12,100
bob,2022-03-13,101
In [63]: df =pandas.read_csv("qiita-table.csv")
In [64]: df
Out[64]:
user date count
0 alice 2022-03-01 1
1 alice 2022-03-05 2
2 alice 2022-03-06 3
3 alice 2022-03-07 4
4 alice 2022-03-12 5
5 alice 2022-03-13 6
6 alice 2022-03-14 7
7 bob 2022-03-12 100
8 bob 2022-03-13 101
解決
まずは日付の計算ができるようにするため、date
列の型をstring(object)からdatetime64
型に変換します。
In [65]: df.dtypes
Out[65]:
user object
date object
count int64
dtype: object
In [70]: df["date"] = pandas.to_datetime(df["date"])
In [71]: df.dtypes
Out[71]:
user object
date datetime64[ns]
count int64
dtype: object
確認のため曜日をday
列に追加します。
In [77]: df["day"] = df["date"].dt.day_name()
In [80]: df
Out[80]:
user date count day
0 alice 2022-03-01 1 Tuesday
1 alice 2022-03-05 2 Saturday
2 alice 2022-03-06 3 Sunday
3 alice 2022-03-07 4 Monday
4 alice 2022-03-12 5 Saturday
5 alice 2022-03-13 6 Sunday
6 alice 2022-03-14 7 Monday
7 bob 2022-03-12 100 Saturday
8 bob 2022-03-13 101 Sunday
groupby
関数でユーザごとに分けて、resample
関数で1週間単位に集計します。
In [85]: df.groupby("user").resample("W",on="date", label="left",closed="left").sum()
Out[85]:
count
user date
alice 2022-02-27 3
2022-03-06 12
2022-03-13 13
bob 2022-03-06 100
2022-03-13 101
以上です。
label
引数, closed
引数を指定している理由
label
引数, closed
引数は、rule="W"
のときはデフォルトでright
です。
label
引数, closed
引数は以下の通りです。
label='left'とすると開始日時、label='right'とすると終了日時がラベルとなる。
closed='left'とすると開始日時 <= 期間 < 終了日時となり、closed='right'とすると開始日時 < 期間 <= 終了日時となる。
label
引数, closed
引数を指定しないと、日曜日終わりの1週間単位で集計されます。
In [89]: df.groupby("user").resample("W",on="date").sum()
Out[89]:
count
user date
alice 2022-03-06 6
2022-03-13 15
2022-03-20 7
bob 2022-03-13 201
日曜日始まりで集計したいので、label="left", closed="left"
を指定しました。
Which bin edge label to label bucket with. The default is ‘left’ for all frequency offsets except for ‘M’, ‘A’, ‘Q’, ‘BM’, ‘BA’, ‘BQ’, and ‘W’ which all have a default of ‘right’.
この説明だとよく分からなかったのですが、別サイトに分かりやすい説明がありました。
label="right"
を指定すると、date
が1週間ずれました。
In [88]: df.groupby("user").resample("W",on="date", label="right",closed="left").sum()
Out[88]:
count
user date
alice 2022-03-06 3
2022-03-13 12
2022-03-20 13
bob 2022-03-13 100
2022-03-20 101
補足
日曜日以外で始まる場合
rule="W-MON"
を指定すると、月曜日始まりの1週間単位で集計されます。
In [91]: df.groupby("user").resample("W-MON",on="date",label="left",closed="left").sum()
Out[91]:
count
user date
alice 2022-02-28 6
2022-03-07 15
2022-03-14 7
bob 2022-03-07 201
指定できる値は以下に掲載されています。
感想
rule="W"
のときは、なぜlabel
引数, closed
引数はデフォルトでright
なんでしょうかね?デフォルトがleft
の方が直観的な気がするのですが。。。