【问题标题】:How accelerate an algorithm to find the time overlaps?如何加速算法以找到时间重叠?
【发布时间】:2019-12-16 01:50:55
【问题描述】:

我有一个包含 4 个属性的数据集:

  • 名为“id”(整数)的 id 属性
  • 一个名为“组”的属性(整数)

  • 一个名为“aankomstdt”(日期时间)的准入时间

  • 称为“ontslagdt”的放电时间(日期时间)

数据集看起来像这样:

id    group          aankomstdt                   ontslagdt
 1   A         Thu Nov 14 04:31:00 CET 2019 Thu Nov 14 09:43:00 CET 2019
 2   A         Thu Nov 14 05:38:00 CET 2019 Thu Nov 14 06:19:00 CET 2019
 3   A         Thu Nov 14 05:52:00 CET 2019 Thu Nov 14 09:14:00 CET 2019
 4   A         Thu Nov 14 05:54:00 CET 2019 Thu Nov 14 10:02:00 CET 2019
 5   B         Thu Nov 14 06:06:00 CET 2019 Thu Nov 14 11:22:00 CET 2019

我想计算同时被录取的例子的数量。因此,一个新属性应该为我提供每个患者(id)在他/她的入院时间范围内入院的患者数量。 我创建了以下工作代码:

import pandas as pd
import numpy as np
from datetime import datetime



admission_time = "aankomstdt"
discharge_time = "ontslagdt"
group = 'group'
date_format = '%Y-%m-%d %H:%M:%S'
path = 'D:/Lionel/Formations_DataScience/Rapidminer/Tests_Rapidminer/count_overlaps_sven.xlsx'


def convert_to_datetime(a) :

  a = datetime.strptime(str(a), date_format)
  return a


def interval_overlaps(a, b):
  return min(a[discharge_time], b[discharge_time]) - max(a[admission_time], b[admission_time]) > np.timedelta64(-1)


def count_overlaps(df1):
  return pd.Series([df1.apply(lambda x: interval_overlaps(x, df1.iloc[i]), axis=1).sum() - 1 for i in range(len(df1))], df1.index)
  #return pd.Series([df1.apply(lambda x: interval_overlaps(x, df1.iloc[i]), axis=1).sum() - 1 for i in range(len(df1))])
def rm_main():

  data = pd.read_excel(path)
  data[admission_time] = data[admission_time].apply(convert_to_datetime)
  data[discharge_time] = data[discharge_time].apply(convert_to_datetime)
  data["count"] = data.groupby(group).apply(count_overlaps).values
  return data

但我的原始数据集有大约 70 000 个示例,因此我估计计算时间约为 1 个月(24 小时/24 小时)。 我的问题是:Python 中是否有解决方案可以显着加速该算法?

谢谢你,

【问题讨论】:

  • 查找具有重叠时间的项目的最快方法可能是首先按开始时间对它们进行排序(也许它们已经是?),然后仅与紧随其后的项目进行比较(首先停止不重叠)。我希望这可以在几秒钟内完成。
  • @zvone,感谢您的评论。你有在 Python 中实现你的想法吗?

标签: python python-3.x algorithm overlap


【解决方案1】:

经典是当你只想要一个所有时间的总和。

召回方法如下: 对于每一行,考虑两个事件:

  • {t: row.startAt, kind: 'start'},
  • {t: row.endAt, kind: 'end'}

制作一个大事件数组并按 t asc 排序

best = 0
pool = 0
foreach event:
  if event.kind == 'start':
    pool++
    if pool > best
      best = pool
  else
    pool--

同时访问患者的最大值存储在best中。

解释是这样的:

  • 活动开始时,除了现有访客之外,我们还有一位新访客
  • 活动结束时,访客已离开游泳池。
  • 我们只想跟踪池的长度

在您的情况下,wa 可以适应:为每个患者关联一个池。

下面考虑患者池:[患者.id]=>maxVisitors

patientPool = {}
pool = 0
foreach event:
  if event.kind == 'start':
    patientPool[event.id] = pool
    pool++
    forall id in patientPool
      if pool > patientPool[id]
        patientPool[id] = pool //eventually think about giving a reference to your row for the count instead..
  else
    pool--
    delete patientPool[event.id]

在下面用于说明目的的实现(js)中,70k 行(随机)大约需要 15 秒。对于python,请参考上面的伪算法(差别不大)

我只测试了下面示例的准确性。

let seed = 4;
function random() {
    let x = Math.sin(seed++) * 10000;
    return parseInt((x - Math.floor(x))*1000);
}

let qs = Array(10).fill(0).map(random).reduce((qs, t, i)=>{
  return (i%2 === 0 ? qs.push([{ t, i: i/2 }]) : qs[qs.length - 1].push({ t, i: (i - 1)/2 })), qs
},[]).map(([a,b])=> a.t < b.t ? [{ ...a, open: true }, b] : [{ ...b, open:true}, a])

function go(qs){
  const events = qs.flatMap(x => x).sort((a, b) => a.t - b.t)
  //patients is an array where patients[i] maps to patient.id == i
  const patients = Array(events.reduce((acc,x)=> Math.max(acc, x.i), 0) + 1)
  const patientPool = new Set
  let pool = 0
  events.forEach(ev => {
    if (ev.open) {
      if (!patientPool.has(ev.i)) {
        patients[ev.i] = pool
        patientPool.add(ev.i)
      }
      pool++
      for(let patientI of patientPool){
        if (pool > patients[patientI]) {
          patients[patientI] = pool
        }
      }
    } else {
      pool--
      patientPool.delete(ev.i)
    }
  })
  return patients
}
console.time('disp')
const res = go(qs)
console.log('go', qs, res)
console.timeEnd('disp')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 2022-01-20
    • 1970-01-01
    • 2011-01-29
    相关资源
    最近更新 更多