python pandas按组建立时间序列计数

时间:2017-10-03 16:45:03

标签: python pandas time-series aggregate

我有一个包含用户订阅服务的表。

当用户状态发生变化时,表格中会插入一个新行,其中包含相同的user_id,更新的新时间和新状态。

示例表:

example = {'updated_at':['2017-01-01', '2017-01-01', '2017-01-02','2017-01-02', '2017-01-03','2017-01-03','2017-01-03','2017-01-04','2017-01-04'],
           'user_id': [9, 10, 11, 12, 13, 12, 14, 11, 10],
           'status': ['trial', 'cancelled', 'trial', 'trial', 'trial', 'active', 'active', 'active', 'active']}

example_data = pd.DataFrame.from_dict(example)

我正在尝试构建的是一个表格,显示按日期状态分组的用户数。如果从一天到另一天没有变化,那么表格应该在两天都显示相同的数据。

如果其中一个用户更新了其状态,那么从那一天开始,这些列应反映新的状态细分。

期望的结果示例:

print desired_results
          date  n     status
0   2017-01-01  0     active
1   2017-01-01  1  cancelled
2   2017-01-01  1      trial
3   2017-01-02  0     active
4   2017-01-02  1  cancelled
5   2017-01-02  3      trial
6   2017-01-03  2     active
7   2017-01-03  1  cancelled
8   2017-01-03  4      trial
9   2017-01-04  4     active
10  2017-01-04  0  cancelled
11  2017-01-04  2      trial

到目前为止我尝试过:

(example_data.
 groupby(['updated_at','status']). #group by date and status
 count(). # count in each group
 unstack(fill_value = 0). # unstack
 cumsum(). # cumsum for each status
 stack(). # stack all together again
 reset_index().rename(columns={'user_id': 'n'})) # rename column and reindex 

但这并没有给我我希望的东西。问题是我将更新计为新记录,因此用户被重复计算。

任何人都可以帮忙吗?

2 个答案:

答案 0 :(得分:0)

我不确定你想要什么,但似乎这会起作用?

(example_data.
  groupby(['updated_at','status']). #group by date and status
  count(). # count in each group
  unstack(fill_value = 0). # unstack
  stack(). # stack all together again
  reset_index().rename(columns={'user_id': 'n'})) # rename column and reindex 

答案 1 :(得分:0)

我意识到我实际上必须做的只是“继续”#39;每个日期的每个用户的先前观察结果,然后只做一个简单的groupby并计算。

我在SO上发现了这个answer关于如何在Groupby中重新索引日期,这让我走上了正确的轨道。

我的解决方案如下:

def reindex_by_date(df):
    dates = ['2017-01-01','2017-01-02','2017-01-03','2017-01-04']
    return df.reindex(dates, method = 'ffill')

(example_data.
 groupby('user_id').
 apply(reindex_by_date).
 reset_index(0, drop=True).
 reset_index().
 groupby(['status', 'index']).
 count().
 reset_index().
 sort_values(['index','status']).
 rename(columns={'index':'date'})
)

上述内容似乎有点多余,可能有更简洁的方法。