LoginSignup
4
4

More than 1 year has passed since last update.

pandas:ユーザごとに1週間単位で集計する

Last updated at Posted at 2022-03-14

実行環境

  • Python 3.10.2
  • pandas 1.4.1

やりたいこと

以下のデータを、userごとに1週間単位(日曜日始まり)の合計のcountを算出したいです。

data.csv
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の方が直観的な気がするのですが。。。

4
4
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
4
4