如何使用cython创建自定义numpy dtype

时间:2012-11-02 16:21:49

标签: python numpy cython

使用C here创建自定义numpy dtypes的示例:

此外,它seems to be possible在cython中创建自定义ufunc:

似乎也应该可以使用cython创建一个dtype(然后为它创建自定义ufunc)。可能吗?如果是这样,你可以发一个例子吗?

使用案例:

我想做一些生存分析。基本数据元素是具有相关审查值的生存时间(浮点数)(如果关联时间表示失败时间,则为False;如果相反表示审查时间,则为True)(即,在观察期间未发生故障)。

显然,我可以使用两个numpy数组来存储这些值:时间的float数组和censor值的bool数组。但是,我想说明事件发生多次的可能性(这是一个很好的模型,比如心脏病发作 - 你可以拥有多个)。在这种情况下,我需要一个对象数组,我称之为MultiEvent。每个MultiEvent包含一系列浮点数(未经审查的失败时间)和一个观察期(也是一个浮点数)。请注意,所有MultiEvent的失败次数并不相同。

我需要能够对MultiEvent s:

的数组执行一些操作
  1. 获取每个

  2. 的失败次数
  3. 获取审查时间(即观察时间减去所有失败时间的总和)

  4. 根据其他参数数组(例如危险值数组)计算对数似然。例如,单个MultiEvent M和持续危险值h的对数可能性如下:

    sum(log(h) + h*t for t in M.times) - h*(M.period - sum(M.times))

  5. 其中M.times是失败时间的列表(数组,等等),M.period是总观察期。我希望适用适当的numpy广播规则,以便我能做到:

    log_lik = logp(M_vec,h_vec)
    

    只要M_vech_vec的尺寸兼容,它就会有效。

    我目前的实施使用numpy.vectorize。这对于1和2来说效果很好,但它对于3来说太慢了。还要注意我不能做this因为我的MultiData对象中的失败次数未提前知道。

2 个答案:

答案 0 :(得分:1)

Numpy数组最适合具有固定大小的数据类型。如果数组中的对象不是固定大小(例如MultiEvent),则操作会变慢。

我建议你将所有生存时间存储在一个包含3个字段的1d线性记录数组中:event_id,time,period。每个事件都可以在数组中出现多个时间:

>>> import numpy as np
>>> rawdata = [(1, 0.4, 4), (1, 0.6, 6), (2,2.6, 6)]
>>> npdata = np.rec.fromrecords(rawdata, names='event_id,time,period')
>>> print npdata
[(1, 0.40000000000000002, 4) (1, 0.59999999999999998, 6) (2, 2.6000000000000001, 6)]

要获取特定索引的数据,您可以使用花式索引:

>>> eventdata = npdata[npdata.event_id==1]
>>> print eventdata
[(1, 0.40000000000000002, 4) (1, 0.59999999999999998, 6)]

这种方法的优点是您可以轻松地将其与基于ndarray的函数集成。您也可以按照manual

中的说明从cython访问此数组
cdef packed struct Event:
    np.int32_t event_id
    np.float64_t time
    np.float64_6 period

def f():
    cdef np.ndarray[Event] b = np.zeros(10,
        dtype=np.dtype([('event_id', np.int32),
                        ('time', np.float64),
                        ('period', np.float64)]))
    <...>

答案 1 :(得分:0)

我为没有直接回答这个问题而道歉,但我之前遇到过类似的问题,如果我理解正确的话,你现在遇到的真正问题是你有可变长度的数据,这真的,真的不是numpy的优点之一,也是你遇到性能问题的原因。除非您事先知道多个事件的最大条目数,否则您将遇到问题,即使这样,您也会浪费大量内存/磁盘空间来填充那些非多事件事件的零。

您的数据点包含多个字段,其中一些字段与其他字段相关,其中一些字段需要在组中进行标识。这强烈暗示您应该考虑使用某种形式的数据库来存储此信息,包括性能,内存,磁盘空间和理智原因。

对于一个刚接触您的代码的人来说,理解一个简单的数据库模式要比一个复杂的,黑客攻击的结构更加容易,这种结构会令人沮丧地缓慢而臃肿。相比之下,SQL查询可以快速轻松地编写。

我建议根据我对你的解释使用Event和MultiEvent表的理解,其中每个Event条目都有一个外键进入MultiEvent表中。