我是Pandas的新手,正在尝试计算屏幕时间。基本上是用户在工作站上解锁屏幕的时间。数据如下:
User Action ActionTime
0 User1 logon 1/1/2020 8:00
1 User1 lock 1/1/2020 12:00
2 User1 unlock 1/1/2020 13:00
3 User1 logoff 1/1/2020 16:00
现在我正试图将登录操作(登录和解锁(和注销操作(注销和锁定(合并到带有时间戳的单行上。示例:
Action_x ActionTime_x Action_y ActionTime_y
User
User1 logon 1/1/2020 8:00 lock 1/1/2020 12:00
User1 unlock 1/1/2020 13:00 logoff 1/1/2020 16:00
为了实现这一点,我尝试将登录和注销操作放入它们自己的数据帧中,然后尝试将它们合并在一起。
logon = df[df["Action"].isin(["logon","unlock"])]
logon.set_index("User", inplace= True)
logoff = df[df["Action"].isin(["logoff","lock"])]
logoff.set_index("User", inplace= True)
merged = pd.merge(logon, logoff, right_index=True, left_index=True)
我在输出中得到的是:
Action_x ActionTime_x Action_y ActionTime_y
User
User1 logon 1/1/2020 8:00 lock 1/1/2020 12:00
User1 logon 1/1/2020 8:00 logoff 1/1/2020 16:00
User1 unlock 1/1/2020 13:00 lock 1/1/2020 12:00
User1 unlock 1/1/2020 13:00 logoff 1/1/2020 16:00
很明显,关于合并,我还有很多东西要学。合并后是否可以执行此操作,或者我遗漏了什么。
编辑:在本例中,User是我的数据帧索引。
与其合并,不如采用另一种方法:
-
若要为每个用户获得单独的结果,请对DataFrame进行分组用户。
-
对每组行(针对特定用户(应用一个函数其中:
- 对Action.isin(['logon','unlock'].cumsum((执行二级分组。这样,登录或解锁的操作中的每一行都会启动一个新组(实际上由2行组成,第二行在这对中是关于锁或注销的行(
- 每个此类组的结果应包含:
- 登录操作-第一行的操作
- 开始-从第一行开始的ActionTime
- 注销操作-最后一行的操作
- 停止最后一行的ActionTime
这样做的代码是:
-
定义要应用于每组行的函数对于当前用户:
def act(grp): return grp.sort_values('ActionTime').groupby(grp.Action.isin(['logon', 'unlock']) .cumsum()).agg(**{'Login Action': ('Action', 'first'), 'Start': ('ActionTime', 'first'), 'Logoff Action': ('Action', 'last'), 'Stop': ('ActionTime', 'last')})
为了在列名中有空格,我使用了字典拆包。
-
将其应用于每组:
result = df.groupby('User').apply(act).reset_index(level=1, drop=True)
附加元素是删除不必要的索引级别。
为了提供一个更具指导性的例子,我创建了DataFrame(适用于2个用户(为:
User Action ActionTime
0 User1 logon 2020-01-01 08:00:00
1 User1 lock 2020-01-01 12:00:00
2 User1 unlock 2020-01-01 13:00:00
3 User1 logoff 2020-01-01 16:00:00
4 User2 logon 2020-01-01 08:15:00
5 User2 lock 2020-01-01 08:17:00
6 User2 unlock 2020-01-01 09:22:00
7 User2 logoff 2020-01-01 09:35:00
我的代码的结果是:
Login Action Start Logoff Action Stop
User
User1 logon 2020-01-01 08:00:00 lock 2020-01-01 12:00:00
User1 unlock 2020-01-01 13:00:00 logoff 2020-01-01 16:00:00
User2 logon 2020-01-01 08:15:00 lock 2020-01-01 08:17:00
User2 unlock 2020-01-01 09:22:00 logoff 2020-01-01 09:35:00
我假设您的DataFrame按ActionTime排序,或者全局或至少针对每个用户(实际上,按user和ActionTime,所以我没有包含任何排序。如果不满足此条件,请添加排序,例如在act函数中:
return grp.sort_values('ActionTime').groupby(...)