Подтвердить что ты не робот

Как создать собственный dtype numpy с помощью cython

Примеры создания пользовательских типов numpy с помощью < здесь:

Кроме того, возможно для создания пользовательских ufuncs в cython:

Похоже, что также возможно создать dtype с использованием cython (а затем создать для него пользовательские ufunc). Является ли это возможным? Если да, можете ли вы отправить пример?

ИСПОЛЬЗОВАТЬ СЛУЧАЙ:

Я хочу провести анализ выживаемости. Основными элементами данных являются время выживания (поплавки) со связанными цензорами (False, если связанное время представляет собой время отказа и True, если вместо этого оно представляет собой время цензуры (т.е. Ни один сбой не произошел в течение периода наблюдения)).

Очевидно, я мог бы использовать два массива numpy для хранения этих значений: массив float для времени и массив bool для значений цензуры. Тем не менее, я хочу учитывать возможность события, происходящего несколько раз (это хорошая модель, например, для сердечных приступов - у вас может быть более одного). В этом случае мне нужен массив объектов, который я называю MultiEvent s. Каждый MultiEvent содержит последовательность поплавков (время без цензуры) и период наблюдения (также плавающий). Обратите внимание, что количество ошибок не одинаково для всех MultiEvent s.

Мне нужно выполнить несколько операций над массивом MultiEvent s:

  • Получите количество отказов для каждого

  • Получить время с цензурой (то есть период наблюдения минус сумма всех времен отказа)

  • Рассчитайте логарифмическое правдоподобие на основе дополнительных массивов параметров (таких как массив значений опасности). Например, логарифмическая вероятность для одного MultiEvent M и значения постоянной опасности h будет выглядеть примерно так:

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

где M.times - это список (массив, независимо) времени сбоя и M.period - общий период наблюдения. Я хочу, чтобы правильные правила широковещания были применены, чтобы я мог:

log_lik = logp(M_vec,h_vec)

и он будет работать до тех пор, пока размеры M_vec и h_vec совместимы.

В моей текущей реализации используется numpy.vectorize. Это работает достаточно хорошо для 1 и 2, но это слишком медленно для 3. Обратите внимание также, что я не могу сделать этот, потому что количество отказов в моих объектах MultiData неизвестно заранее.

4b9b3361

Ответ 1

Массивы Numpy наиболее подходят для типов данных с фиксированным размером. Если объекты в массиве не являются фиксированным размером (например, MultiEvent), операции могут стать значительно медленнее.

Я бы порекомендовал вам хранить все время выживания в линейном массиве 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. Вы также можете получить доступ к этим массивам из 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)]))
    <...>

Ответ 2

Я извиняюсь за то, что не ответил на вопрос напрямую, но раньше у меня были подобные проблемы, и если я правильно понял, реальная проблема, с которой вы сейчас сталкиваетесь, заключается в том, что у вас есть данные переменной длины, что на самом деле не реально одна из сильных сторон numpy, и именно поэтому вы столкнулись с проблемами производительности. Если вы заранее не знаете максимальное количество записей для мультивещества, у вас появятся проблемы, и даже тогда вы будете тратить массу пространства памяти/дискового пространства, заполненного нулями, для тех событий, которые не являются несколькими событиями.

У вас есть точки данных с несколькими полями, некоторые из которых связаны с другими полями, а некоторые из них необходимо идентифицировать в группах. Это наводит на мысль, что вы должны рассматривать базу данных определенной формы для хранения этой информации, для обеспечения производительности, памяти, пробела на диске и соображений здравомыслия.

Для человека, нового для вашего кода, будет намного проще понять простую схему базы данных, чем сложная структура с взломом на numpy, которая будет разочаровывающе медленной и раздутой. SQL-запросы быстро и легко записываются в сравнении.

Я хотел бы предложить на основе моего понимания вашего объяснения с таблицами Event и MultiEvent, где каждая запись события имеет внешний ключ в таблице MultiEvent, где это необходимо.