python - 有没有一种基于另一个数据框中的数据创建数据框列的有效方法?
问题描述
我有两个数据框。一个包含用户订阅数据,另一个包含用户会话数据。
订阅数据示例 (df_subscriptions):
user_id created ended
10238 140baa7a-1641-41b5-a85b-c43dc9e12699 2021-08-13 19:37:11.373039 2021-09-12 19:37:11.373039
10237 fbfa999c-9c56-4f06-8cf9-3c5deb32d5d2 2021-08-13 15:25:07.149982 2021-09-12 15:25:07.149982
6256 a55e64b0-a783-455e-bd9d-edbb4815786b 2021-08-13 18:31:36.083681 2021-09-12 18:31:36.083681
6257 ca2c0ee1-9810-4ce7-a2ec-c036d0b8a380 2021-08-13 16:29:52.981836 2021-09-12 16:29:52.981836
7211 24378efd-e821-4a51-a3e6-39c30243a078 2021-08-13 19:58:19.434908 2021-09-12 19:58:19.434908
会话数据示例:
user_id session_start session_duration
11960653 6f51df1a-8c2b-4ddb-9299-b36f250b05dc 2020-01-05 11:39:29.367 165.880005
80076 697e1c0a-c026-4104-b13f-1fd74eec5890 2021-01-31 02:16:33.935 22.883301
1577621 02b23671-8ce3-452b-b551-03b5ea7dce47 2021-05-18 02:07:32.589 4.283300
1286532 a506fb53-3505-44db-880a-27ad483151f0 2020-07-29 16:47:51.908 51.000000
18875432 1ea77db5-fe4a-414f-ba47-1f448175df3f 2020-10-17 04:00:35.269 360.733307
我需要计算用户在订阅处于活动状态时在服务上花费的总时间。下面的代码给了我正确/预期的结果,但在真实数据上花费了很多时间:
def sessions_during_sub (user_id, start_date, end_date):
result = df_sessions.loc[(df_sessions.user_id == user_id)&
(df_sessions.session_start >= start_date)&
(df_sessions.session_start <= end_date)].session_duration.sum()
return result
df_subscriptions['sessions'] = df_subscriptions.apply(lambda x: sessions_during_sub(x['user_id'], x['created'], x['ended']), axis=1)
有没有办法做到正确的熊猫方式/矢量化?关于如何真正加快速度的任何想法。
解决方案
创建一些示例数据:
subs = pd.DataFrame(zip(["user_0", "user_0", "user_1", "user_2"], [1900, 1920, 1950, 2000], [1910, 1930, 2000, 2020]), columns=["user_id", "created", "ended"])
user_id created ended
0 user_0 1900 1910
1 user_0 1920 1930
2 user_1 1950 2000
3 user_2 2000 2020
sessions = pd.DataFrame(zip(["user_0", "user_0", "user_0", "user_2"], [1905, 1915, 1925, 2005], [1.0, 5.0, 2.0, 7.0]), columns=["user_id", "session_start", "session_duration"])
user_id session_start session_duration
0 user_0 1905 1.0
1 user_0 1915 5.0
2 user_0 1925 2.0
3 user_2 2005 7.0
合并的目的是创建一个表,所有订阅和会话数据都在同一行中。这类似于sessions_during_sub
在您问题的代码中应用时在两个数组中的所有行中循环检查 user_id 相等性:
merged = pd.merge(subs, sessions, on="user_id")
user_id created ended session_start session_duration
0 user_0 1900 1910 1905 1.0
1 user_0 1900 1910 1915 5.0
2 user_0 1900 1910 1925 2.0
3 user_0 1920 1930 1905 1.0
4 user_0 1920 1930 1915 5.0
5 user_0 1920 1930 1925 2.0
6 user_2 2000 2020 2005 7.0
每个用户拥有多个订阅和多个会话在这里不是问题,您只会得到包含一些重复数据的多个结果行。然后,您可以编写一些逻辑来检查订阅范围,如下所示:
in_subscription_range = (merged.session_start >= merged.created) & (merged.session_start < merged.ended)
最后计算会话持续时间的总和,例如每个 user_id,如下所示:merged[in_subscription_range].groupby("user_id").session_duration.sum()
user_id
user_0 3.0
user_2 7.0
Name: session_duration, dtype: float64
如果您的原始数据包含时间上重叠的订阅或会话,您需要在合并之前修复它,否则您可能会多次计算持续时间。但是您的示例代码也存在同样的问题。
推荐阅读
- azure-functions - CosmosDBTrigger 可靠地处理每个文档一次?
- javascript - 带有象限和线 x,y 的自定义 charts.js
- css - 如何通过打字稿更新 CSS
- python - 我无法为倒置图填充颜色,也无法自定义 y 轴。谁能帮我这个?
- mule - 如何从mule 4中的json中获取数组值
- html - 是否可以定位具有某些 CSS 样式的元素?
- azure - 移动租户但将 API / 应用程序保留在当前 Azure AD 中
- python - glob.glob() 返回空列表
- android - SwipeLayout - 无法解析 attr.xml 中的符号“drag_edge”
- angular - 日期管道:LOCALE_ID 不影响时区?