在Pandas中,每个用户只需要特定数量的日期

时间:2017-02-01 15:36:51

标签: python pandas

假设我有包含usersidid(int)和date(datatime)的df:

 usersidid  date
1   1   2017-01-05
2   2   2017-01-02
3   3   2017-01-04
4   4   2017-01-02
5   1   2017-01-01
6   2   2017-01-03
7   3   2017-01-02
8   1   2017-01-04
9   2   2017-01-05

我有@timeframe,@ MinDates的参数。 我需要检查每个用户ID ,如果从今天到今天(@timeframe),数据帧中有足够的不同MinDates,如果不是程序需要退出。我会说:

示例A -

@timeframe = 5
@MinDates = 1
today = 2017-01-05

在这种情况下结果:

usersidid   date
1   1   2017-01-01
2   1   2017-01-04
3   1   2017-01-05
4   2   2017-01-02
5   2   2017-01-03
6   2   2017-01-05
7   3   2017-01-02
8   3   2017-01-04
9   4   2017-01-02

示例B -

@timeframe = 5
@MinDates = 2
today = 2017-01-05

在这种情况下结果:

  usersidid date
1   1   2017-01-01
2   1   2017-01-04
3   1   2017-01-05
4   2   2017-01-02
5   2   2017-01-03
6   2   2017-01-05
7   3   2017-01-02
8   3   2017-01-04

示例C -

@timeframe = 5
@MinDates = 3
today = 2017-01-05

在这种情况下结果:

 usersidid  date
1   1   2017-01-01
2   1   2017-01-04
3   1   2017-01-05
4   2   2017-01-02
5   2   2017-01-03
6   2   2017-01-05

示例D -

@timeframe = 5
@MinDates = 4
today = 2017-01-05 

在这种情况下结果:在时间范围内没有足够的不同日期,退出程序

示例E -

@timeframe = 3
@MinDates = 2
today = 2017-01-05

在这种情况下结果(由Ted Petrou修复):

  usersidid   date
1    1      2017-01-04
2    1      2017-01-05
3    2      2017-01-03
4    2      2017-01-05

我的想法一般:

agg1 = df[today >= timedelta(days=@dataframe) + df.date]
agg2 = agg1.groupby(['usersidid'], as_index=False, sort=False)['date'].countunique().rename(columns={'date': 'NumOfDifferentDates'})
agg3 = agg2[agg2.NumOfDifferentDates >= @MinDates]
result = df[df.usersidid.isin(agg3.loc[:, 'usersidid'])].reset_index(drop=True)]
if result.empty() exit(0)

我还没有运行它所以我不知道它是否有效,因为我是Pandas的新手,我确信有一种更优雅的方式来做我想听到的。

谢谢,

1 个答案:

答案 0 :(得分:1)

您可以编写一个函数,它接受三个参数todaytimeframemindates,并首先使用布尔索引将数据帧过滤到时间范围内的行。在此处,您可以按useridid进行分组,并过滤​​掉不等于或超过mindates的群组。

def find_dates(today, timeframe, mindates):
    prev = today - np.timedelta64(timeframe-1, 'D')
    df_new = df[df.date.between(prev, today)]
    return df_new.groupby('usersidid').filter(lambda x: len(x) >= mindates).sort_values(['usersidid', 'date'])

today = pd.to_datetime('2017-01-05')

现在您可以使用您的特定参数调用您的函数。

find_dates(today, 5, 1)

       usersidid       date
5          1 2017-01-01
8          1 2017-01-04
1          1 2017-01-05
2          2 2017-01-02
6          2 2017-01-03
9          2 2017-01-05
7          3 2017-01-02
3          3 2017-01-04
4          4 2017-01-02

find_dates(today, 5, 2)

   usersidid       date
5          1 2017-01-01
8          1 2017-01-04
1          1 2017-01-05
2          2 2017-01-02
6          2 2017-01-03
9          2 2017-01-05
7          3 2017-01-02
3          3 2017-01-04

find_dates(today, 5, 3)

   usersidid       date
5          1 2017-01-01
8          1 2017-01-04
1          1 2017-01-05
2          2 2017-01-02
6          2 2017-01-03
9          2 2017-01-05

find_dates(today, 5, 4)
# returns empty dataframe

我不明白你的最后一个结果是如何使用timeframe = 3和mindates = 2的。 useridid 1和2在过去三天内都有两行。

find_dates(today, 3, 2)

   usersidid       date
8          1 2017-01-04
1          1 2017-01-05
6          2 2017-01-03
9          2 2017-01-05