pandas - 如何检查日期的连续顺序并复制它们的分组?

3

首先我有两个问题,第一个如下:
我有一个包含许多相同userid、日期和一些不重要的其他列的数据框df:

    userid   date        
0    243     2014-04-01   
1    234     2014-12-01   
2    234     2015-11-01   
3    589     2016-07-01   
4    589     2016-03-01   

我目前正在尝试按userid分组并按日期降序排序,并剔除最旧的12个。我的代码如下:

df = df.groupby(['userid'], group_keys=False).agg(lambda x: x.sort_values(['date'], ascending=False, inplace=False).head(12))

我遇到了一个错误:
ValueError: cannot copy sequence with size 6 to array axis with dimension 12

目前我的目标是避免将数据框拆分为单个数据框。


我的第二个问题更加复杂:
我试图找出排序后的日期(分别按用户ID组)是否是每月连续的。这意味着如果有一个用户ID组的日期,例如用户ID:234和日期:2014-04-01,则下面的下一个条目必须是用户ID:234和日期:2014-03-01。重点不在于日期,只有年份和月份很重要。只有这连续的12个日期应该被复制到另一个数据框中。
第二个数据框df2包含相同的用户ID,但它们是唯一的,并且另一列是“代码”。以下是一个示例:

         userid  code
0          433805  1
24          5448   0
48          3434   1
72          34434  1
96          3202   1
120         23766  1
153         39457  0
168         4113   1
172         3435   5
374         34093  1

我总结一下:我尝试检查每个用户ID是否有12个连续的月份,并将每个正确的序列复制到另一个数据框中。为此,我还需要比较df2中的'code'。
这是我的代码版本:

df['YearMonthDiff'] = df['date'].map(lambda x: 1000*x.year + x.month).diff()
    df['id_before'] = df['userid'].shift()
    final_df = pd.DataFrame()
    for group in df.groupby(['userid'], group_keys=False):
        fi = group[1]
        if (fi['userid'] <> fi['id_before']) &  group['YearMonthDiff'].all(-1.0) & df.loc[fi.userid]['code'] != 5:
            final_df.append(group['userid','date', 'consum'])

一开始是从一个整数日期计算并生成diff()函数。在其他帖子上,我看到他们移动列以比较当前行和前一行的值。然后我使用groupby(userid)来迭代单个组。现在变得更加丑陋了。我试图找到这样一个userid组的开头,尝试检查是否只有连续的月份和正确的'code'。最后,我将其附加到最终数据框中。
其中最大的问题之一是将一行与下一行进行比较。我可以使用iterrow()对它们进行迭代,但是如果没有shift()函数就无法进行比较。存在一个日历函数,但在周末我会查看一下。抱歉我是pandas的新手。
有人有解决我的问题的想法吗?

最好每个问题只问一个问题。 - Stephen Rauch
3个回答

3

针对您的第一个问题,尝试以下方法:

df.groupby(by='userid').apply(lambda x: x.sort_values(by='date',ascending=False).iloc[[e for e in range(12) if e <len(x)]])

2
使用groupbynlargest,我们可以得到最大日期的索引值。然后使用.loc只获取这些行。
df.loc[df.groupby('userid').date.nlargest(12).index.get_level_values(1)]

考虑数据框 df
dates = pd.date_range('2015-08-08', periods=10)
df = pd.DataFrame(dict(
        userid=np.arange(2).repeat(4),
        date=np.random.choice(dates, 8, False)
    ))

print(df)

        date  userid
0 2015-08-12       0  # <-- keep
1 2015-08-09       0
2 2015-08-11       0
3 2015-08-15       0  # <-- keep
4 2015-08-13       1
5 2015-08-10       1
6 2015-08-17       1  # <-- keep
7 2015-08-16       1  # <-- keep

我们将保留每个用户ID的最新2个日期。
df.loc[df.groupby('userid').date.nlargest(2).index.get_level_values(1)]

        date  userid
0 2015-08-12       0
3 2015-08-15       0
6 2015-08-17       1
7 2015-08-16       1

非常接近了,但我要搜索最近的12个月: df = df.drop( ~ df.groupby('userid')['date'].nlargest(12).index.get_level_values(1)) 我想要最近的12个月,并删除所有其他条目。我用~符号展示了这一点,但当然它只是按位运算。我该如何删除所有其他条目? - haapoo

0
也许有人会感兴趣,我这样解决了我的第二个问题:
我将日期转换为整数,计算差值,然后将userid向下移动一行,就像我的例子一样。然后接下来...在stackoverflow上找到了一个解决方案
gr_ob = df.groupby('userid')
gr_dict = gr_ob.groups
final_df = pd.DataFrame(columns=['userid', 'date', 'consum'])
for group_name in gr_dict.keys():
        new_df = gr_ob.get_group(group_name)
        if (new_df['userid'].iloc[0] <> new_df['id_before'].iloc[0]) & (new_df['YearMonthDiff'].iloc[1:] == -1.0).all() & (len(new_df) == 12):
            final_df = final_df.append(new_df[['userid', 'date', 'consum']])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接