Cython Typing Список строк
Я пытаюсь использовать Cython для улучшения производительности цикла, но я сталкиваюсь с некоторыми проблемами, объявляя типы входов.
Как мне включить поле в моей типизированной структуре, которая является строкой, которая может быть "передней" или "задней"
у меня есть np.recarray
это выглядит следующим образом (обратите внимание, что длина повторного массива неизвестна во время компиляции)
import numpy as np
weights = np.recarray(4, dtype=[('a', np.int64), ('b', np.str_, 5), ('c', np.float64)])
weights[0] = (0, "front", 0.5)
weights[1] = (0, "back", 0.5)
weights[2] = (1, "front", 1.0)
weights[3] = (1, "back", 0.0)
а также ввод списка строк и pandas.Timestamp
import pandas as pd
ts = pd.Timestamp("2015-01-01")
contracts = ["CLX16", "CLZ16"]
Я пытаюсь цитонизировать следующий цикл
def ploop(weights, contracts, timestamp):
cwts = []
for gen_num, position, weighting in weights:
if weighting != 0:
if position == "front":
cntrct_idx = gen_num
elif position == "back":
cntrct_idx = gen_num + 1
else:
raise ValueError("transition.columns must contain "
"'front' or 'back'")
cwts.append((gen_num, contracts[cntrct_idx], weighting, timestamp))
return cwts
Моя попытка заключалась в наборе weights
ввод в виде структуры в Cython, в файле struct_test.pyx
следующее
import numpy as np
cimport numpy as np
cdef packed struct tstruct:
np.int64_t gen_num
char[5] position
np.float64_t weighting
def cloop(tstruct[:] weights_array, contracts, timestamp):
cdef tstruct weights
cdef int i
cdef int cntrct_idx
cwts = []
for k in xrange(len(weights_array)):
w = weights_array[k]
if w.weighting != 0:
if w.position == "front":
cntrct_idx = w.gen_num
elif w.position == "back":
cntrct_idx = w.gen_num + 1
else:
raise ValueError("transition.columns must contain "
"'front' or 'back'")
cwts.append((w.gen_num, contracts[cntrct_idx], w.weighting,
timestamp))
return cwts
Но я получаю ошибки во время выполнения, которые, я считаю, связаны сchar[5] position
,
import pyximport
pyximport.install()
import struct_test
struct_test.cloop(weights, contracts, ts)
ValueError: Does not understand character buffer dtype format string ('w')
Кроме того, мне немного непонятно, как я буду печатать contracts
так же как timestamp
,
1 ответ
Ваш ploop
(без timestamp
переменная) производит:
In [226]: ploop(weights, contracts)
Out[226]: [(0, 'CLX16', 0.5), (0, 'CLZ16', 0.5), (1, 'CLZ16', 1.0)]
Эквивалентная функция без цикла:
def ploopless(weights, contracts):
arr_contracts = np.array(contracts) # to allow array indexing
wgts1 = weights[weights['c']!=0]
mask = wgts1['b']=='front'
wgts1['b'][mask] = arr_contracts[wgts1['a'][mask]]
mask = wgts1['b']=='back'
wgts1['b'][mask] = arr_contracts[wgts1['a'][mask]+1]
return wgts1.tolist()
In [250]: ploopless(weights, contracts)
Out[250]: [(0, 'CLX16', 0.5), (0, 'CLZ16', 0.5), (1, 'CLZ16', 1.0)]
Я пользуюсь тем фактом, что возвращаемый список кортежей имеет такую же (int, str, int) компоновку, что и вход weight
массив. Так что я просто делаю копию weights
и замена выбранных значений b
поле.
Обратите внимание, что я использую индекс выбора поля перед mask
один. Логическое значение mask
создает копию, поэтому мы должны внимательно следить за порядком индексации.
Я предполагаю, что версия массива без петель будет конкурентоспособной во времени с cloop
(на реалистичных массивах). Операции со строками и списками в cloop
вероятно, ограничить его ускорение.