Как создать собственный 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 неизвестно заранее.
Ответы
Ответ 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, где это необходимо.