使用 python pandas 计算一个用户对不同电话号码的并发呼叫量的有效方法?

Aza*_*at 5 python group-by dataframe python-3.x pandas

我有一个很大的数据框,其中包含用户呼叫不同电话号码的数据

calls = {
    'user': ['a', 'b', 'b', 'b', 'c', 'c'],
    'number': ['+1 11', '+2 22', '+2 22', '+1 11', '+4 44', '+1 11'],
    'start_time': ['00:00:00', '00:02:00', '00:03:00', '00:00:00', '00:00:00', '00:00:00'],
    'end_time': ['00:05:00', '00:03:01', '00:05:00', '00:05:00', '00:02:00', '00:02:00']
}

df = pd.DataFrame(calls)
Run Code Online (Sandbox Code Playgroud)
用户 数字 开始时间 时间结束
0 A 1 11 00:00:00 00:05:00
1 2 22 00:02:00 00:03:01
2 2 22 00:03:00 00:05:00
3 1 11 00:00:00 00:05:00
4 C 4 44 00:00:00 00:02:00
5 C 1 11 00:00:00 00:02:00

我正在尝试计算从一个用户到一个不同数字的并发(并行)调用的最大数量:

res = pd.DataFrame([])
grouped_by_user = df.groupby(['user'])
user_dict = defaultdict(lambda: {'number_dict': None})
    
    for user in grouped_by_user.groups:
    user_group = grouped_by_user.get_group(user)
    grouped_by_number = user_group.groupby(['number'])
    number_dict = defaultdict(lambda: {'max_calls': None})
    
    for number in grouped_by_number.groups:
        number_group = grouped_by_number.get_group(number)
        calls = []
        for i in number_group.index:
            calls.append(len(number_group[(number_group["start_time"] <= number_group.loc[i, "start_time"]) & (number_group["end_time"] > number_group.loc[i, "start_time"])]))
        number_dict[number]['max_calls'] = max(calls)
    user_dict[user]['number_dict'] = number_dict
    
    tmp_list = []
    for num, calls in number_dict.items():
        tmp_list.append([user, num, calls['max_calls']])
    res = res.append(tmp_list, ignore_index=True)
Run Code Online (Sandbox Code Playgroud)

生成的数据框如下所示:

用户 数字 最大限度
0 A 1 11 1
1 1 11 1
2 2 22 2
3 C 1 11 1
4 C 4 44 1

但对于大型数据帧来说,这段代码非常慢。有更好的方法吗?或者说怎样才能提高这段代码的时间效率呢?

And*_*ely 1

尝试:

df["start_time"] = pd.to_datetime(df["start_time"], format='%H:%M:%S')
df["end_time"] = pd.to_datetime(df["end_time"], format='%H:%M:%S')

def fn(x):
    x["tmp1"] = x.apply(
        lambda y: pd.date_range(y["start_time"], y["end_time"], freq="1s"),
        axis=1,
    )

    x = x.explode("tmp1")

    return (
        x.loc[x.duplicated(subset=["tmp1"], keep=False), "tmp1"]
        .value_counts()
        .max()
    )


print(
    df.groupby(["user", "number"])
    .apply(fn)
    .to_frame(name="max")
    .reset_index()
    .fillna(1)
)
Run Code Online (Sandbox Code Playgroud)

印刷:

  user number  max
0    a  +1 11  1.0
1    b  +1 11  1.0
2    b  +2 22  2.0
3    c  +1 11  1.0
4    c  +4 44  1.0
Run Code Online (Sandbox Code Playgroud)

calls = {
    "user": ["a", "b", "b", "b", "c"],
    "number": ["+1 11", "+1 11", "+1 11", "+1 11", "+1 11"],
    "start_time": ["00:00:00", "00:04:00", "00:00:00", "00:03:00", "00:00:00"],
    "end_time": ["00:05:00", "00:08:00", "00:05:00", "00:05:30", "00:02:00"],
}
Run Code Online (Sandbox Code Playgroud)

印刷:

  user number  max
0    a  +1 11  1.0
1    b  +1 11  3.0
2    c  +1 11  1.0
Run Code Online (Sandbox Code Playgroud)