Здесь вам нужно сразу несколько концепций.
Во-первых, у вас еще нет количества. Из вашего желаемого результата я взял, что вы хотите это ежегодно, но вы можете указать любой период времени, который вы хотите. Затем просто посчитайте с помощью groupby()
и count()
In [66]: df2 = df.groupby([pd.to_datetime(df.date).dt.year, "action", "department"]).count().squeeze().rename("count")
Out[66]:
date action department
2017 close marketing 2
open sales 1
2018 close marketing 1
open marketing 1
other marketing 1
2019 close marketing 1
sales 1
open sales 1
Name: count, dtype: int64
squeeze()
и rename()
есть, потому что после этого столбец подсчета и год будут называться date
, и вы получите имяконфликт. Вы можете эквивалентно использовать rename(columns={'date': 'count'})
и не приводить к Series
.
Второй шаг - pivot_table
. Это создает имена столбцов из значений. Поскольку существуют комбинации date
и action
без соответствующего значения, вам необходимо pivot_table
.
In [62]: df2.pivot_table(index="department", columns=["date", "action"])
Out[62]:
count
date 2017 2018 2019
action close open close open other close open
department
marketing 2.0 NaN 1.0 1.0 1.0 1.0 NaN
sales NaN 1.0 NaN NaN NaN 1.0 1.0
Поскольку NaN
внутренне представлен как плавающий пионт, ваши счета также были преобразованы в плавающую точку. Чтобы это исправить, просто добавьте fillna
и конвертируйте обратно в int
.
In [65]: df2.reset_index().pivot_table(index="department", columns=["date", "action"]).fillna(0).astype(int)
Out[65]:
count
date 2017 2018 2019
action close open close open other close open
department
marketing 2 0 1 1 1 1 0
sales 0 1 0 0 0 1 1
Чтобы получить именно ваш вывод, вам нужно изменить pd.to_datetime(df.date).dt.year
. Вы можете сделать это с помощью strftime
(https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dt.strftime.html). Кроме того, столбец ["2017", "other"] был удален из-за отсутствия значения. Если это создает проблемы, необходимо предварительно включить значения. После первогошаг reindex
и fillna
должны сделать свое дело.
РЕДАКТИРОВАТЬ: Да, это делает
In [77]: new_index = pd.MultiIndex.from_product([[2017, 2018, 2019], ["close", "open", "other"], ['marketing', 'sales']], names=['date', 'action', 'department'])
...:
In [78]: df3 = df2.reindex(new_index).fillna(0).astype(int).reset_index()
Out[78]:
date action department count
0 2017 close marketing 2
1 2017 close sales 0
2 2017 open marketing 0
3 2017 open sales 1
4 2017 other marketing 0
5 2017 other sales 0
6 2018 close marketing 1
.. ... ... ... ...
11 2018 other sales 0
12 2019 close marketing 1
13 2019 close sales 1
14 2019 open marketing 0
15 2019 open sales 1
16 2019 other marketing 0
17 2019 other sales 0
In [79]: df3.pivot_table(index="department", columns=["date", "action"])
Out[79]:
count
date 2017 2018 2019
action close open other close open other close open other
department
marketing 2 0 0 1 1 1 1 0 0
sales 0 1 0 0 0 0 1 1 0