在 pandas 中创建一个数据透视表 table 并同时对每周的日期进行分组

Creating a pivot table in pandas and grouping at the same time the dates per week

我想在 python 中创建一个 pd.pivot_table,其中一列是 datetime 对象,但我还想每周对我的结果进行分组。这是一个简单的例子:我有以下 DataFrame:

import pandas as pd

names = ['a', 'b', 'c', 'd'] * 7
dates = ['2017-01-11', '2017-01-08', '2017-01-14', '2017-01-05', '2017-01-10', '2017-01-13', '2017-01-02', '2017-01-12', '2017-01-10', '2017-01-05', '2017-01-01', '2017-01-04', '2017-01-11', '2017-01-14', '2017-01-05', '2017-01-06', '2017-01-14', '2017-01-11', '2017-01-06', '2017-01-05', '2017-01-08', '2017-01-10', '2017-01-07', '2017-01-04', '2017-01-02', '2017-01-04', '2017-01-01', '2017-01-12']
dates = [pd.to_datetime(i).date() for i in dates]
numbers = [4, 3, 2, 1 ] * 7
data = {'name': names , 'date': dates, 'number': numbers}

df = pd.DataFrame(data)

产生:

          date name  number
0   2017-01-11    a       4
1   2017-01-08    b       3
2   2017-01-14    c       2
3   2017-01-05    d       1
4   2017-01-10    a       4
5   2017-01-13    b       3
6   2017-01-02    c       2
7   2017-01-12    d       1
8   2017-01-10    a       4
9   2017-01-05    b       3
10  2017-01-01    c       2
11  2017-01-04    d       1
12  2017-01-11    a       4
13  2017-01-14    b       3
14  2017-01-05    c       2
15  2017-01-06    d       1
16  2017-01-14    a       4
17  2017-01-11    b       3
18  2017-01-06    c       2
19  2017-01-05    d       1
20  2017-01-08    a       4
21  2017-01-10    b       3
22  2017-01-07    c       2
23  2017-01-04    d       1
24  2017-01-02    a       4
25  2017-01-04    b       3
26  2017-01-01    c       2
27  2017-01-12    d       1

我想创建一个数据透视表 table,其中行将是 姓名 ,列将是 [=38= 上的日期]weekly 基础,数字将是数字列的总和。例如,枢轴 table 的第一行将是:

2017-01-01 2017-01-08 2017-01-15 ... a 4 24 0

我正在做的是:

pd.pivot_table(data=df, values='number', columns=pd.Grouper(key='date', freq='1W'), index='name', aggfunc=sum)

但我收到错误: TypeError: Only valid with DatetimeIndex, TimedeltaIndex or PeriodIndex, but got an instance of 'RangeIndex'.

我该怎么做?我不知道我是否可以使用日期作为索引,因为所有日期值都不是唯一的。

IIUC:

首先确保 date 列是 datetime dtype:

df['date'] = pd.to_datetime(df['date'], errors='coerce')

然后您可以分组、求和和取消堆叠:

In [289]: (df.groupby(['name', pd.Grouper(freq='W', key='date')])
             ['number']
             .sum()
             .unstack(fill_value=0))
Out[289]:
date  2017-01-01  2017-01-08  2017-01-15
name
a              0           8          20
b              0           9          12
c              4           8           2
d              0           5           2

:

In [328]: (df.groupby(['name', pd.Grouper(freq='W', key='date', closed='left')])
             ['number']
             .sum()
             .unstack(fill_value=0))
Out[328]:
date  2017-01-08  2017-01-15
name
a              4          24
b              6          15
c             12           2
d              5           2

In [330]: (df.assign(date=df['date']-pd.offsets.Day(7))
     ...:    .groupby(['name', pd.Grouper(freq='W', key='date', closed='left')])
     ...:    ['number']
     ...:    .sum()
     ...:    .unstack(fill_value=0))
     ...:
Out[330]:
date  2017-01-01  2017-01-08
name
a              4          24
b              6          15
c             12           2
d              5           2

继续我的逻辑,我们可以创建一个 多索引 ,其中 日期 是索引的一部分。所以我们可以有:

import pandas as pd

names = ['a', 'b', 'c', 'd'] * 7
dates = ['2017-01-11', '2017-01-08', '2017-01-14', '2017-01-05', '2017-01-10', '2017-01-13', '2017-01-02', '2017-01-12', '2017-01-10', '2017-01-05', '2017-01-01', '2017-01-04', '2017-01-11', '2017-01-14', '2017-01-05', '2017-01-06', '2017-01-14', '2017-01-11', '2017-01-06', '2017-01-05', '2017-01-08', '2017-01-10', '2017-01-07', '2017-01-04', '2017-01-02', '2017-01-04', '2017-01-01', '2017-01-12']
dates = [pd.to_datetime(i).date() for i in dates]
numbers = [4, 3, 2, 1 ] * 7
data = {'name': names , 'date': dates, 'number': numbers}

df = pd.DataFrame(data)

df.set_index([df.index, df.date], inplace=True)

print pd.pivot_table(data=df, columns=pd.Grouper(freq='7d', level='date', closed='left') , index='name', aggfunc=sum)

这恰好产生:

         number           
date 2017-01-01 2017-01-08
name                      
a             4         24
b             6         15
c            12          2
d             5          2
df.groupby(['name', 'date'])['number'].sum().unstack()

说明:

  1. 按名称和日期分组。
  2. 从组中选择号码
  3. 对所有数字求和并展开