Python 如何使用cython创建自定义numpy数据类型
以下是使用C创建自定义numpy数据类型的示例: 此外,还需要在cython中创建自定义UFUNC: 似乎还可以使用cython创建一个数据类型(然后为其创建自定义UFUNC)。可能吗?如果是,你能举个例子吗 用例: 我想做一些生存分析。基本数据元素是具有相关审查值的生存时间(浮动)(如果相关时间表示故障时间,则为假;如果相关时间表示审查时间,则为真(即观察期间未发生故障)) 显然,我可以使用两个numpy数组来存储这些值:一个用于times的float数组和一个用于censor值的bool数组。然而,我想解释一个事件发生多次的可能性(这是一个很好的模型,比如说,心脏病发作——你可以有不止一次)。在这种情况下,我需要一个对象数组,我称之为Python 如何使用cython创建自定义numpy数据类型,python,numpy,cython,Python,Numpy,Cython,以下是使用C创建自定义numpy数据类型的示例: 此外,还需要在cython中创建自定义UFUNC: 似乎还可以使用cython创建一个数据类型(然后为其创建自定义UFUNC)。可能吗?如果是,你能举个例子吗 用例: 我想做一些生存分析。基本数据元素是具有相关审查值的生存时间(浮动)(如果相关时间表示故障时间,则为假;如果相关时间表示审查时间,则为真(即观察期间未发生故障)) 显然,我可以使用两个numpy数组来存储这些值:一个用于times的float数组和一个用于censor值的bool数组
MultiEvent
s。每个多事件
包含一系列浮动(未经检测的故障时间)和一个观察期(也是一个浮动)。请注意,并非所有多事件
s的故障数都相同
我需要能够对MultiEvent
s数组执行一些操作:
多事件M
和恒定危险值h
的对数可能性如下:
sum(对数(h)+h*t表示t的M倍)-h*(M.period-sum(M倍))
M.times
是故障时间列表(数组,无论什么),而M.period
是总观察期。我希望适用适当的numpy广播规则,以便我能够:
log_lik = logp(M_vec,h_vec)
只要M_-vec
和h_-vec
的维度兼容,它就可以工作
我当前的实现使用
numpy.vectorize
。这对于1和2来说已经足够好了,但是对于3来说太慢了。另外请注意,我不能这样做,因为我的多数据对象中的失败次数事先还不知道。我为没有直接回答这个问题而道歉,但我以前也遇到过类似的问题,如果我理解正确,您现在遇到的真正问题是您有可变长度的数据,这实际上是,这不是numpy的优势之一,也是您遇到性能问题的原因。除非您事先知道多事件的最大条目数,否则您将遇到问题,即使这样,对于那些不是多事件的事件,您也将浪费大量的内存/磁盘空间,这些空间中充满了零
您有多个字段的数据点,其中一些字段与其他字段相关,一些字段需要在组中标识。这强烈提示您应该考虑某种形式的数据库来存储这些信息,包括性能、内存、磁盘空间和理智原因。
对于代码新手来说,理解一个简单的数据库模式要比理解一个复杂的、被黑客攻击过的numpy结构容易得多,而numpy结构的速度会令人沮丧地缓慢和臃肿。相比之下,SQL查询编写起来又快又容易
根据我对您解释的理解,我建议使用事件表和多事件表,其中每个事件条目在相关的多事件表中都有一个外键。Numpy数组最适合固定大小的数据类型。如果数组中的对象大小不固定(例如多重事件),则操作可能会慢得多 我建议您将所有生存时间存储在一个1d线性记录数组中,该数组有3个字段:事件id、时间、周期。每个事件可以在数组中多次出现:
>>> 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的函数集成。您还可以从cython访问此阵列,如中所述:
cdef压缩结构事件:
np.int32\u t事件\u id
np.64\t时间
np.64_6期间
def():
cdef np.ndarray[Event]b=np.zero(10,
dtype=np.dtype([('event_id',np.int32),
(“时间”,第64页),
(“期间”,np.64)])
您之所以这样问是因为您发现编写cython比编写C更简单吗?我怀疑如果可能的话(我不知道),您最终会得到与C一样复杂和混乱的代码,因此可能没有任何好处。@DaveP有两个原因。一个是我发现用cython编写代码比用C编写更简单。另一个是我希望让python程序员能够轻松地为新的数据类型和ufunc重复这个过程。我希望我能包装大部分的复杂性,并使定义数据类型在cython中成为一件简单的事情。也就是说,cython是我上周才知道的东西。我一直在玩它,但目前我还不完全了解它的功能。如果有一个用例,我们可以帮助您考虑使用这个解决方案,那就太好了。问题是,我无法使用已经构建在numpy之上的大量工具。这个答案的一个扩展是基于我的多事件表和保存标量变量的表之间的连接创建一个numpy数组(或数据帧)。然而,出于我的目的(使用一组特定的pymc模型),不幸的是,这也不是一个选项。@user1572508您考虑过类似的东西吗?
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)]))
<...>