n3a*_*e3r 6 python group-by pandas
我想计算数据集中发生的三向对话的数量。聊天group_x可以由多个成员组成。
什么是三方对话?
red_x 在 group_x 中发送消息。green_x 在同一组_x 中回复。red_x 在同一个 group_x 中发送回复。这可以称为三方对话。
序列必须恰好是 red_#、green_#、red_#。
什么是接触点?
用于轻松生成我正在使用的示例数据集的代码。
import pandas as pd
from pandas import Timestamp
t1_df = pd.DataFrame({'from_red': [True, False, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, True],
'sent_time': [Timestamp('2021-05-01 06:26:00'), Timestamp('2021-05-04 10:35:00'), Timestamp('2021-05-07 12:16:00'), Timestamp('2021-05-07 12:16:00'), Timestamp('2021-05-09 13:39:00'), Timestamp('2021-05-11 10:02:00'), Timestamp('2021-05-12 13:10:00'), Timestamp('2021-05-12 13:10:00'), Timestamp('2021-05-13 09:46:00'), Timestamp('2021-05-13 22:30:00'), Timestamp('2021-05-14 14:14:00'), Timestamp('2021-05-14 17:08:00'), Timestamp('2021-06-01 09:22:00'), Timestamp('2021-06-01 21:26:00'), Timestamp('2021-06-03 20:19:00'), Timestamp('2021-06-03 20:19:00'), Timestamp('2021-06-09 07:24:00'), Timestamp('2021-05-01 06:44:00'), Timestamp('2021-05-01 08:01:00'), Timestamp('2021-05-01 08:09:00')],
'w_uid': ['w_000001', 'w_112681', 'w_002516', 'w_002514', 'w_004073', 'w_005349', 'w_006803', 'w_006804', 'w_008454', 'w_009373', 'w_010063', 'w_010957', 'w_066840', 'w_071471', 'w_081446', 'w_081445', 'w_106472', 'w_000002', 'w_111906', 'w_000003'],
'user_id': ['red_00001', 'green_0263', 'red_01071', 'red_01071', 'red_01552', 'red_01552', 'red_02282', 'red_02282', 'red_02600', 'red_02854', 'red_02854', 'red_02600', 'red_00001', 'red_09935', 'red_10592', 'red_10592', 'red_12292', 'red_00002', 'green_0001', 'red_00003'],
'group_id': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
'touchpoint': [1, 2, 1, 3, 1, 3, 1, 3, 1, 1, 3, 3, 3, 1, 1, 3, 1, 1, 2, 1]},
columns = ['from_red', 'sent_time', 'w_uid', 'user_id', 'group_id', 'touchpoint'])
t1_df['sent_time'] = pd.to_datetime(t1_df['sent_time'], format = "%d-%m-%Y")
t1_df
Run Code Online (Sandbox Code Playgroud)
数据集如下所示:
| 来自_红色 | 发送时间 | w_uid | 用户身份 | 组ID | 接触点 |
|---|---|---|---|---|---|
| 真的 | 2021-05-01 06:26:00 | w_000001 | 红色_00001 | 0 | 1 |
| 错误的 | 2021-05-04 10:35:00 | w_112681 | 绿色_0263 | 0 | 2 |
| 真的 | 2021-05-07 12:16:00 | w_002516 | 红_01071 | 0 | 1 |
| 真的 | 2021-05-07 12:16:00 | w_002514 | 红_01071 | 0 | 3 |
| 真的 | 2021-05-09 13:39:00 | w_004073 | 红色_01552 | 0 | 1 |
| 真的 | 2021-05-11 10:02:00 | w_005349 | 红色_01552 | 0 | 3 |
| 真的 | 2021-05-12 13:10:00 | w_006803 | 红色_02282 | 0 | 1 |
| 真的 | 2021-05-12 13:10:00 | w_006804 | 红色_02282 | 0 | 3 |
| 真的 | 2021-05-13 09:46:00 | w_008454 | 红_02600 | 0 | 1 |
| 真的 | 2021-05-13 22:30:00 | w_009373 | 红色_02854 | 0 | 1 |
| 真的 | 2021-05-14 14:14:00 | w_010063 | 红色_02854 | 0 | 3 |
| 真的 | 2021-05-14 17:08:00 | w_010957 | 红_02600 | 0 | 3 |
| 真的 | 2021-06-01 09:22:00 | w_066840 | 红色_00001 | 0 | 3 |
| 真的 | 2021-06-01 21:26:00 | w_071471 | 红色_09935 | 0 | 1 |
| 真的 | 2021-06-03 20:19:00 | w_081446 | 红色_10592 | 0 | 1 |
| 真的 | 2021-06-03 20:19:00 | w_081445 | 红色_10592 | 0 | 3 |
| 真的 | 2021-06-09 07:24:00 | w_106472 | 红色_12292 | 0 | 1 |
| 真的 | 2021-05-01 06:44:00 | w_000002 | 红色_00002 | 1 | 1 |
| 错误的 | 2021-05-01 08:01:00 | w_111906 | 绿色_0001 | 1 | 2 |
| 真的 | 2021-05-01 08:09:00 | w_000003 | 红色_00003 | 1 | 1 |
这是我尝试过的,但查询花费的时间太长。有没有更快的方法来达到同样的目的?
test_df = pd.DataFrame()
for i in range(len(t1_df['sent_time'])-1):
if t1_df.query(f"group_id == {i}")['from_red'].nunique() == 2:
y = t1_df.query(f"group_id == {i} & touchpoint == 2").loc[:, ['sent_time']].values[0][0]
x = t1_df.query(f"group_id == {i} & sent_time > @y & (touchpoint == 3)").sort_values('sent_time')
test_df = pd.concat([test_df, x])
test_df.merge(x, how = "outer")
else:
pass
test_df
Run Code Online (Sandbox Code Playgroud)
对我来说,不清楚你如何定义“三向对话”。在小组内,如果您收到消息,input您认为什么选项是“三向对话”?有几种选择:
Input : red_0, red_2, green_0, red_1, red_0, red_2, red_1
Option1: red_2, green_0, red_1
Option2: red_0, green_0, red_0
+ : red_2, green_0, red_2
Run Code Online (Sandbox Code Playgroud)
还有很多。您的代码示例在绿色之后返回用户的第二条消息:
OptionX: green_0, red_0
+ : green_0, red_2
+ : green_0, red_1
Run Code Online (Sandbox Code Playgroud)
不跟踪是否有红色用户在绿色用户之前发送了一条消息。另一个问题是,如果绿色在一组内发送多次,会发生什么情况。
Input : red_0, red_2, green_0, green_0, red_1, red_0, green_1, red_1
Run Code Online (Sandbox Code Playgroud)
根据您的描述“顺序必须准确red_#, green_#, red_#”。我想, Option1 就是您正在寻找的,也许它甚至独立于 color: color0_#, color1_#, color0_#。如我错了请纠正我 ;)。
为了使操作更通用,我首先准备 DataFrame,例如提取用户的颜色并获取颜色的整数表示
Input : red_0, red_2, green_0, red_1, red_0, red_2, red_1
Option1: red_2, green_0, red_1
Option2: red_0, green_0, red_0
+ : red_2, green_0, red_2
Run Code Online (Sandbox Code Playgroud)
color0_#, color1_#, color0_#OptionX: green_0, red_0
+ : green_0, red_2
+ : green_0, red_1
Run Code Online (Sandbox Code Playgroud)
返回并适用于任何颜色
Input : red_0, red_2, green_0, green_0, red_1, red_0, green_1, red_1
Run Code Online (Sandbox Code Playgroud)
通过 DataFrame 准备,您可以轻松计算组内每个颜色或用户的消息,或者从颜色或用户获取消息的第一次和最后一次时间。之后cumcount更快。countpd.merg()
# extract the user color and id
t1_df[['color', 'id']] = t1_df.pop('user_id').str.split('_', expand=True)
# get the dtypes right, also it is not needed here
t1_df.id = t1_df.id.astype(int)
t1_df.color = t1_df.color.astype('category')
# get color as intager
t1_df['color_as_int'] =pd.factorize(t1_df.color)[0]
Run Code Online (Sandbox Code Playgroud)