首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在根据两个不同列的日期获得交叉连接表的唯一记录时,如何提高逻辑的速度/内存?

在根据两个不同列的日期获得交叉连接表的唯一记录时,如何提高逻辑的速度/内存?
EN

Stack Overflow用户
提问于 2021-08-22 12:36:44
回答 1查看 43关注 0票数 2

我之前问过关于根据两个不同列的日期获取交叉表的唯一记录的问题吗?这里:Previous Question, Context and Answer

虽然所提供的答案有效:

代码语言:javascript
复制
import numpy as np

# df - your DataFrame

group = df.groupby(['P_CLIENT_ID', 'P_DATE_ENCOUNTER'])

def foo(df):
    result = df.loc[df.P_DATE_ENCOUNTER>df.R_DATE_TESTED, ['R_DATE_TESTED', 'R_RESULT']].tail(1).reset_index()
    if not result.empty:
        return result
    else:
        return pd.DataFrame([[np.nan, np.nan, np.nan]], columns=['RECORD_ID','R_DATE_TESTED', 'R_RESULT'])


group.apply(foo)

我的实际数据文件有+- 1.5百万行,这个.apply花了两个小时的时间,并在笔记本上使用了大量内存,最终会崩溃。应用同样的逻辑有内存效率吗?我想也许用dense-ranknp.where

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-08-22 13:49:43

您可以通过使用所有矢量化的Pandas操作(Pandas内置函数)来加快进程,这些操作已经被Pandas优化为快速运行,而不是使用.apply()和自定义函数( Pandas无法优化和缓慢运行)。

我们首先将R_DATE_TESTEDR_RESULT的值替换为NaN,再用Series.where()代替。然后,使用groupby() + last()获取所需的聚合条目,如下所示:

Series.where()使用

  1. R_DATE_TESTEDR_RESULT的值替换为NaN (如果R_DATE_TESTED < R_DATE_ENCOUNTER不是真的话)

代码语言:javascript
复制
df['R_DATE_TESTED'] = df['R_DATE_TESTED'].where(df['R_DATE_TESTED'] < df['P_DATE_ENCOUNTER'])
df['R_RESULT'] = df['R_RESULT'].where(df['R_DATE_TESTED'] < df['P_DATE_ENCOUNTER'])

  1. 使用groupby() + last()在每个组中获取最近的(和非NaN)条目:

代码语言:javascript
复制
df.groupby(['P_CLIENT_ID', 'P_DATE_ENCOUNTER'], as_index=False).last()

输出:

代码语言:javascript
复制
   P_CLIENT_ID P_DATE_ENCOUNTER  RECORD_ID  R_CLIENT_ID R_DATE_TESTED  R_RESULT
0        25835       2016-12-21     302956      25835.0          None       NaN
1        25835       2017-02-21     302963      25835.0          None       NaN
2        25835       2017-04-25     302970      25835.0    2017-03-07      20.0
3        25835       2017-06-21     302977      25835.0    2017-03-07      20.0
4        25835       2017-09-04     302984      25835.0    2017-08-03      20.0
5        25835       2018-01-08     302991      25835.0    2017-08-03      20.0
6        25835       2018-04-03     302998      25835.0    2018-03-23      20.0
7        25835       2018-07-25     303005      25835.0    2018-03-23      20.0

执行时间基准

1.样本数据大小: 56行

旧解决方案:

代码语言:javascript
复制
%%timeit
group = df.groupby(['P_CLIENT_ID', 'P_DATE_ENCOUNTER'])

def foo(df):
    result = df.loc[df.P_DATE_ENCOUNTER>df.R_DATE_TESTED, ['R_DATE_TESTED', 'R_RESULT']].tail(1).reset_index()
    if not result.empty:
        return result
    else:
        return pd.DataFrame([[np.nan, np.nan, np.nan]], columns=['RECORD_ID','R_DATE_TESTED', 'R_RESULT'])


group.apply(foo)


16.5 ms ± 94.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

新解决方案:

代码语言:javascript
复制
%%timeit
df['R_DATE_TESTED'] = df['R_DATE_TESTED'].where(df['R_DATE_TESTED'] < df['P_DATE_ENCOUNTER'])
df['R_RESULT'] = df['R_RESULT'].where(df['R_DATE_TESTED'] < df['P_DATE_ENCOUNTER'])
df.groupby(['P_CLIENT_ID', 'P_DATE_ENCOUNTER'], as_index=False).last()

4.24 ms ± 146 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

样本数据大小为56行的,新解决方案比快近4倍(16.5ms减至4.24ms)

2.扩大的数据大小:168万行

代码语言:javascript
复制
df2 = pd.concat([df] * 30000, ignore_index=True)

df2.shape
(1680000, 6)       # 1.68 million rows

新解决方案:

代码语言:javascript
复制
%%timeit
df2['R_DATE_TESTED'] = df2['R_DATE_TESTED'].where(df2['R_DATE_TESTED'] < df2['P_DATE_ENCOUNTER'])
df2['R_RESULT'] = df2['R_RESULT'].where(df2['R_DATE_TESTED'] < df2['P_DATE_ENCOUNTER'])
df2.groupby(['P_CLIENT_ID', 'P_DATE_ENCOUNTER'], as_index=False).last()

473 ms ± 7.37 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

新解决方案只需不到1秒就可完成处理.

由于扩大的数据集大多是重复的数据,运行时间可能与实际数据的情况不成线性比例。无论如何,这表明对于大型数据集来说,新解决方案的运行时间仍然是合理的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68881383

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档