【问题标题】:How to create a custom numpy dtype using cython如何使用 cython 创建自定义 numpy dtype
【发布时间】:2012-10-23 08:20:20
【问题描述】:

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

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

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

用例:

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

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

我需要能够对MultiEvents 的数组执行一些操作:

  1. 获取每个失败的次数

  2. 获取删失时间(即观察时间减去所有失效时间的总和)

  3. 根据其他参数数组(例如危险值数组)计算对数似然度。例如,单个 MultiEvent M 和恒定危险值 h 的对数似然值类似于:

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

其中M.times 是故障时间列表(数组,等等),M.period 是总观察期。我希望应用适当的 numpy 广播规则,以便我可以这样做:

log_lik = logp(M_vec,h_vec)

只要M_vech_vec 的尺寸兼容,它就可以工作。

我当前的实现使用numpy.vectorize。这对于 1 和 2 来说足够好,但对于 3 来说太慢了。还要注意,我不能这样做 this,因为我的 MultiData 对象中的失败次数事先不知道。

【问题讨论】:

  • 您问的原因是因为您发现编写 cython 比编写 C 更简单吗?我怀疑如果可能的话(我不知道),你最终会得到和 C 一样复杂和混乱的代码,所以可能没有任何好处。
  • @DaveP 有两个原因。一个是我发现用 cython 编写比 C 更简单。另一个是我想让这个过程更容易让 python 程序员重复新的 dtypes 和 ufuncs。我希望我可以包装大部分复杂性并使定义 dtypes 在 cython 中成为一件简单的事情。也就是说,cython 是我上周才了解到的。我一直在玩它,但目前我并不完全了解它的功能。
  • 最好有一个用例,以便我们为您提供帮助
  • 你考虑过使用pandas

标签: python numpy cython


【解决方案1】:

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

我建议您将所有生存时间存储在具有 3 个字段的一维线性记录数组中:event_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 访问此数组,如 manual 中所述:

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)]))
    <...>

【讨论】:

    【解决方案2】:

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

    您的数据点包含多个字段,其中一些与其他字段相关,还有一些需要分组识别。这强烈暗示,出于性能、内存、磁盘空间和健全性的原因,您应该考虑使用某种形式的数据库来存储这些信息。

    对于刚接触您的代码的人来说,理解简单的数据库架构要比理解复杂的 numpy 结构要容易得多,后者会非常缓慢和臃肿。相比之下,SQL 查询快速且易于编写。

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

    【讨论】:

    • 这个解决方案的问题是我无法使用已经构建在 numpy 之上的大量工具。这个答案的扩展是基于我的 MultiEvent 表和保存我的标量变量的表之间的连接创建一个 numpy 数组(或 pandas DataFrame)。但是,出于我的目的(使用一组特定的 pymc 模型),这也不是一个选项。
    • @user1572508 你考虑过类似PyTables的东西吗?
    猜你喜欢
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多