在pandas数据帧中计算每月新值的数量

时间:2018-01-04 23:11:43

标签: python-2.7 pandas

我有一个巨大的列表(pandas dataframe),看起来像这样

            user    userID    
Date    
1/1/2018    Annual    12345
1/3/2018    Annual    12345
1/5/2018    One Time  
1/11/2018   One Time   
1/12/2018   One Time   
1/13/2018   Annual    98765
.
.
2/1/2018    Annual    12345
2/3/2018    Annual    12345
2/5/2018    One Time  
2/11/2018   One Time   
2/12/2018   One Time   
2/13/2018   Annual    98765

这是用户活动历史记录的列表。每次有人使用此服务时,都会记录下来。有年度会员和一次性用户。

我想要做的是计算每月新的会员购买次数。

会员资格有效期为一年,所以我假设如果会员资格是在2017年1月1日购买的,则用户ID 11111有效期至2017年12月31日。在上面的示例列表中,用户12345使用了该服务两次,但第二个不应该计数,因为用户12345在2014年1月1日购买了年度会员资格。同样,用户12345s在2/1/2018上的活动不应该算作新会员购买,因为它是在2017年1月1日购买的。

并且还假设年度会员资格是在他们使用第一笔服务作为年度会员资格时购买的。(用户ID 12345在2014年1月1日购买了他/她的会员资格)

修改

例如

import numpy as np
import pandas as pd
from random import randint
from random import randrange
from datetime import timedelta
from datetime import datetime

start = datetime.strptime('1/1/2017', '%m/%d/%Y')
end = datetime.strptime('12/31/2017', '%m/%d/%Y')

def random_date(start, end):
    delta = end - start
    int_delta = (delta.days * 24 * 60 * 60) + delta.seconds
    random_second = randrange(int_delta)
    return start + timedelta(seconds=random_second)

userIDs = []
dates = []
userType = []

for i in range(10000):
    userIDs.append( randint(100, 999))
    dates.append( random_date(start, end) )
    userType.append( randint(1, 2) )

df = pd.DataFrame({'ID': userIDs, 'date':dates, 'type': userType})
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace = True)

1 个答案:

答案 0 :(得分:0)

您可以尝试分组(按年份和用户ID,然后按年份和月份),但使用到期日需要进行多次操作。我相信更机械的解决方案可以非常简单地处理这个问题。

from dateutil.relativedelta import relativedelta


count = {}  # month's number of subscriptions
since = {}  # member's date of subscription
for i, r in df[df.type==1].sort_values('date').iterrows():
    if r.ID in since and r.date < since[r.ID] + relativedelta(years=1):
        continue  # valid member, not counting
    since[r.ID] = r.date

    ym = r.date.year, r.date.month
    count[ym] = count.setdefault(ym, 0) + 1

我不想将日期视为索引,因为两个成员应该能够同时遵守。

按顺序打印count会产生类似的内容:

(2017, 1) 94
(2017, 2) 7
(2018, 1) 76
(2018, 2) 20
(2018, 3) 5
(2019, 1) 50
(2019, 2) 39
(2019, 3) 10
(2019, 4) 2