使用PADAS将带有填充零的序列号附加到序列

问题描述

我有如下所示的数据帧

df = pd.DataFrame({'person_id': [101,101,101,101,202,202,202],
                        'login_date':['5/7/2013 09:27:00 AM','09/08/2013 11:21:00 AM','06/06/2014 08:00:00 AM','06/06/2014 05:00:00 AM','12/11/2011 10:00:00 AM','13/10/2012 12:00:00 AM','13/12/2012 11:45:00 AM']})
df.login_date = pd.to_datetime(df.login_date)
df['logout_date'] = df.login_date + pd.Timedelta(days=5)
df['login_id'] = [1,1,1,1,8,8,8]

正如您在示例数据框中看到的那样,尽管loginlogout日期对于个人而言不同,但login_id是相同的。

例如,person = 101在4个不同的时间戳登录和注销。但他具有相同的LOGIN_ID,这是不正确的。

相反,我希望生成一个new login_id列,其中每个人都会获得一个新的login_id,但在随后的登录中会保留1st login_id信息。因此,我们可以知道它是一个序列

我尝试了以下方法,但效果不佳

df.groupby(['person_id','login_date','logout_date'])['login_id'].rank(method="first", ascending=True) + 100000

我希望我的输出如下所示。您可以看到18是如何在随后的login_ids中保留每个人的第一个login_id的。我们只需添加00001,然后根据行数加上一个序列即可。

请注意,我想将此应用于大数据,login_ids可能不仅仅是实际数据中的single digit。对于ex,第一个login_id甚至可以是576869578等类型的随机数。在这种情况下,后续登录id将为57686957800001。希望这能帮上忙。无论该主题的第一个login_id是什么,请根据此人的行数添加0000100002等。希望这对您有帮助


解决方案

更新2:刚刚意识到我之前的答案也使第一个索引增加了100000。以下是使用GroupBy.transform()仅将100000添加到后续索引的版本:

cumcount = df.groupby(['person_id','login_id']).login_id.cumcount()
df.login_id = df.groupby(['person_id','login_id']).login_id.transform(
    lambda x: x.shift().mul(100000).fillna(x.min())
).add(cumcount)

    person_id           login_date          logout_date  login_id
# 0       101  2013-05-07 09:27:00  2013-05-12 09:27:00         1
# 1       101  2013-09-08 11:21:00  2013-09-13 11:21:00    100001
# 2       101  2014-06-06 08:00:00  2014-06-11 08:00:00    100002
# 3       101  2014-06-06 05:00:00  2014-06-11 05:00:00    100003
# 4       202  2011-12-11 10:00:00  2011-12-16 10:00:00         8
# 5       202  2012-10-13 00:00:00  2012-10-18 00:00:00    800001
# 6       202  2012-12-13 11:45:00  2012-12-18 11:45:00    800002

更新:更快的选择是使用GroupBy.cumcount()

构建序列
cumcount = df.groupby(['person_id','login_id']).login_id.cumcount()
df.login_id = df.login_id.mul(100000).add(cumcount)

#   person_id           login_date          logout_date  login_id
# 0       101  2013-05-07 09:27:00  2013-05-12 09:27:00    100000
# 1       101  2013-09-08 11:21:00  2013-09-13 11:21:00    100001
# 2       101  2014-06-06 08:00:00  2014-06-11 08:00:00    100002
# 3       101  2014-06-06 05:00:00  2014-06-11 05:00:00    100003
# 4       202  2011-12-11 10:00:00  2011-12-16 10:00:00    800000
# 5       202  2012-10-13 00:00:00  2012-10-18 00:00:00    800001
# 6       202  2012-12-13 11:45:00  2012-12-18 11:45:00    800002

您可以在GroupBy.apply()中构建序列:

df.login_id = df.groupby(['person_id','login_id']).login_id.apply(
    lambda x: pd.Series([x.min()*100000+seq for seq in range(len(x))], x.index)
)

相关文章