在python中,什么';识别n个事件t个时间间隔的集群最有效的方法是什么?

在python中,什么';识别n个事件t个时间间隔的集群最有效的方法是什么?,python,Python,例如,如果我有以下事件数据,并且希望找到至少包含两个事件的集群,这些事件彼此之间的间隔不超过1分钟,其中id_1、id_2和id_3都相同。作为参考,除了日期时间戳之外,我还有历元时间戳(以微秒为单位) event_id timestamp id_1 id_2 id_3 9442823 Jun 15, 2015 10:22 PM PDT A 1 34567 9442821 Jun 15, 2015 10:22 PM PDT A 2 1234

例如,如果我有以下事件数据,并且希望找到至少包含两个事件的集群,这些事件彼此之间的间隔不超过1分钟,其中id_1、id_2和id_3都相同。作为参考,除了日期时间戳之外,我还有历元时间戳(以微秒为单位)

event_id       timestamp          id_1 id_2  id_3
9442823 Jun 15, 2015 10:22 PM PDT   A   1   34567
9442821 Jun 15, 2015 10:22 PM PDT   A   2   12345
9442817 Jun 15, 2015 10:22 PM PDT   A   3   34567
9442814 Jun 15, 2015 10:22 PM PDT   A   1   12345
9442813 Jun 15, 2015 10:22 PM PDT   A   2   34567
9442810 Jun 15, 2015 10:22 PM PDT   A   3   12345
9442805 Jun 15, 2015 10:22 PM PDT   A   1   34567
9442876 Jun 15, 2015 10:23 PM PDT   A   2   12345
9442866 Jun 15, 2015 10:23 PM PDT   A   3   34567
9442858 Jun 15, 2015 10:23 PM PDT   A   1   12345
9442845 Jun 15, 2015 10:23 PM PDT   C   2   34567
9442840 Jun 15, 2015 10:23 PM PDT   C   3   12345
9442839 Jun 15, 2015 10:23 PM PDT   C   1   34567
9442838 Jun 15, 2015 10:23 PM PDT   C   2   12345
9442907 Jun 15, 2015 10:24 PM PDT   C   3   34567
9442886 Jun 15, 2015 10:24 PM PDT   C   1   12345
9442949 Jun 15, 2015 10:25 PM PDT   C   2   34567
9442934 Jun 15, 2015 10:25 PM PDT   C   3   12345

对于找到的每个集群,我想返回一组(id_1、id_2、id_3、[事件id列表]、集群的最小时间戳、集群的最大时间戳)。此外,如果有一个包含(例如)6个事件的集群,我只想返回一个包含所有事件的结果,而不是每个包含3个事件的分组返回一个结果。

如果我正确理解了您的问题,您可以使用scikit learn的DBSCAN聚类算法和自定义距离(或度量)函数。如果id_1、id_2或id_3中的任何一个不同,则距离函数应返回一个非常大的数字。否则就是应该返回时差

但使用这种方法时,簇的数量由算法决定,而不是作为算法的输入。如果您决定将集群数量作为输入传递,那么k-means是您可能需要研究的集群算法。

在纯python中,使用一个“滑动窗口”,它包含1分钟范围内的所有事件

前提很简单:维护一个作为子序列的事件队列 在总列表中,按顺序排列。“窗口”(队列)应该是您关心的所有事件。在这种情况下,这取决于60秒的时间间隔要求

在处理事件时,将一个事件添加到队列末尾。如果队列中的第一个事件距离新添加的最后一个事件的时间超过60秒,请通过从队列前面删除第一个事件向前滑动窗口

这是蟒蛇3:

import collections
import operator
import itertools

from datetime import datetime

#### FROM HERE: vvv is just faking events. Delete or replace.

class Event(collections.namedtuple('Event', 'event_id timestamp id_1 id_2 id_3 epoch_ts')):
    def __str__(self):
        return ('{e.event_id} {e.timestamp}  {e.id_1}  {e.id_2}  {e.id_3}'
                .format(e=self))

def get_events():
    event_list = map(operator.methodcaller('strip'), '''
        9442823 Jun 15, 2015 10:22 PM PDT   A   1   34567
        9442821 Jun 15, 2015 10:22 PM PDT   A   2   12345
        9442817 Jun 15, 2015 10:22 PM PDT   A   3   34567
        9442814 Jun 15, 2015 10:22 PM PDT   A   1   12345
        9442813 Jun 15, 2015 10:22 PM PDT   A   2   34567
        9442810 Jun 15, 2015 10:22 PM PDT   A   3   12345
        9442805 Jun 15, 2015 10:22 PM PDT   A   1   34567
        9442876 Jun 15, 2015 10:23 PM PDT   A   2   12345
        9442866 Jun 15, 2015 10:23 PM PDT   A   3   34567
        9442858 Jun 15, 2015 10:23 PM PDT   A   1   12345
        9442845 Jun 15, 2015 10:23 PM PDT   C   2   34567
        9442840 Jun 15, 2015 10:23 PM PDT   C   3   12345
        9442839 Jun 15, 2015 10:23 PM PDT   C   1   34567
        9442838 Jun 15, 2015 10:23 PM PDT   C   2   12345
        9442907 Jun 15, 2015 10:24 PM PDT   C   3   34567
        9442886 Jun 15, 2015 10:24 PM PDT   C   1   12345
        9442949 Jun 15, 2015 10:25 PM PDT   C   2   34567
        9442934 Jun 15, 2015 10:25 PM PDT   C   3   12345
    '''.strip().splitlines())

    for line in event_list:
        idev, *rest = line.split()
        ts = rest[:6]
        id1, id2, id3 = rest[6:]
        id2 = int(id2)  # faster when sorting (see find_clustered_events)
        id3 = int(id3)  # faster when sorting (see find_clustered_events)
        ts_str = ' '.join(ts)
        dt = datetime.strptime(ts_str.replace('PDT', '-0700'), '%b %d, %Y %I:%M %p %z')
        epoch = dt.timestamp()
        ev = Event(idev, ts_str, id1, id2, id3, epoch)
        yield ev

#### TO HERE: ^^^  was just faking up your events. Delete or replace.


def add_cluster(key, group):
    '''Do whatever you want with the clusters. I'll print them.'''

    print('Cluster:', key)
    print('    ','\n    '.join(map(str, group)), sep='')


def find_clustered_events(events, cluster=3, gap_secs=60):
    '''Call add_cluster on clusters of events within a maximum time gap.

    Args:
        events (iterable): series of events, in chronological order
        cluster (int): minimum number of events in a cluster
        gap_secs (float): maximum time-gap from start to end of cluster

    Returns:
        None.

    '''
    window = collections.deque()
    evkey = lambda e: (e.id_1, e.id_2, e.id_3)

    for ev in events:
        window.append(ev)

        t0 = window[0].epoch_ts
        tn = window[-1].epoch_ts

        if tn - t0 < gap_secs:
            continue

        window.pop()

        for k, g in itertools.groupby(sorted(window, key=evkey), key=evkey):
            group = tuple(g)
            if len(group) >= cluster:
                add_cluster(k, group)

        window.append(ev)
        window.popleft()

# Call find_clustered with event generator, cluster args. 
# Note that your data doesn't have any 3-clusters without time seconds. :-(

find_clustered_events(get_events(), cluster=2)
请注意:上面的代码并不试图跟踪集群中已有的事件。例如,如果您有一个每15秒发生一次的事件类型,您将有一个如下的序列:

$ python test.py
Cluster: ('A', 1, 34567)
    9442823 Jun 15, 2015 10:22 PM PDT  A  1  34567
    9442805 Jun 15, 2015 10:22 PM PDT  A  1  34567
Cluster: ('A', 2, 12345)
    9442821 Jun 15, 2015 10:22 PM PDT  A  2  12345
    9442876 Jun 15, 2015 10:23 PM PDT  A  2  12345
Cluster: ('A', 3, 34567)
    9442817 Jun 15, 2015 10:22 PM PDT  A  3  34567
    9442866 Jun 15, 2015 10:23 PM PDT  A  3  34567
Cluster: ('A', 1, 12345)
    9442814 Jun 15, 2015 10:22 PM PDT  A  1  12345
    9442858 Jun 15, 2015 10:23 PM PDT  A  1  12345
Cluster: ('C', 2, 34567)
    9442845 Jun 15, 2015 10:23 PM PDT  C  2  34567
    9442949 Jun 15, 2015 10:25 PM PDT  C  2  34567
 event1   t=0:00
 event2   t=0:15
 event3   t=0:30
 event4   t=0:45
 event5   t=1:00
您将得到重叠的簇:

event1, event2, event3 (t=0:00 .. 0:30)
event2, event3, event4 (t=0:15 .. 0:45)
event3, event4, event5 (t=0:30 .. 1:00)
从技术上讲,这些都是有效的集群,每个集群略有不同。但是,如果希望事件仅出现在单个集群中,则可能希望从窗口中删除以前聚集的事件

或者,如果集群和重复的机会很低,那么在
add_cluster()
函数中实现重复检查可能会提高性能,从而减少主循环所做的工作

最后一点注意:这会进行大量排序。而且排序效率不高,因为每次出现新事件时都会重复排序。如果数据集很大,性能可能会很差。如果事件键相对较少(也就是说,如果id1,2,3值趋向于反复重复),则最好为每个不同的键(id1+id2+id3)动态创建单独的deque,并将事件分派到适当的deque,应用相同的窗口逻辑,然后检查deque的长度


另一方面,如果您正在处理web服务器日志之类的东西,请求者总是在更改,那么可能会导致所有无用的数据出现内存问题。因此,这是内存与时间的权衡。

因此,这可能是一个csv?数据当前在熊猫数据框中,但我不认为这是数据格式。