使用 pandas 计算群聊数据集中三向对话的数量

n3a*_*e3r 6 python group-by pandas

我想计算数据集中发生的三向对话的数量。聊天group_x可以由多个成员组成。

什么是三方对话?

  1. 第一种方式 - red_x 在 group_x 中发送消息。
  2. 第二种方式 - green_x 在同一组_x 中回复。
  3. 第三种方式 - red_x 在同一个 group_x 中发送回复。

这可以称为三方对话。

序列必须恰好是 red_#、green_#、red_#。

什么是接触点?

  1. 接触点 1 - red_x 的第一条消息。
  2. 接触点 2 - green_x 的第一条消息。
  3. 接触点 3 - red_x 的第二条消息。

用于轻松生成我正在使用的示例数据集的代码。

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)

kho*_*kho 1

对我来说,不清楚你如何定义“三向对话”。在小组内,如果您收到消息,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)