Попытка реализовать декоратор jit для увеличения скорости выполнения моего кода. Не получение должного результата. Он проходит через все виды ошибок. Ключевая ошибка, ошибки типа и т. д. Фактический код без numba работает без проблем.
# The Code without numba is:
df = pd.DataFrame()
df['Serial'] = [865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880]
df['Value'] = [586,586.45,585.95,585.85,585.45,585.5,586,585.7,585.7,585.5,585.5,585.45,585.3,584,584,585]
df['Ref'] = [586.35,586.1,586.01,586.44,586.04,585.91,585.47,585.99,585.35,585.27,585.32,584.86,585.36,584.18,583.53,585]
df['Base'] = [0,-1,1,1,1,1,-1,0,1,1,1,0,1,1,0,-1]
df['A'] = 0.0
df['B'] = 0.0
df['Counter'] = 0
df['Counter'][0] = df['Serial'][0]
for i in range(0,len(df)-1):
# Filling Column 'A'
if (df.iloc[1+i,2] > df.iloc[1+i,1]) & (df.iloc[i,5] > df.iloc[1+i,1]) & (df.iloc[1+i,3] >0):
df.iloc[1+i,4] = round((df.iloc[1+i,1]*1.02),2)
elif (df.iloc[1+i,2] < df.iloc[1+i,1]) & (df.iloc[i,5] < df.iloc[1+i,1]) & (df.iloc[1+i,3] <0):
df.iloc[1+i,4] = round((df.iloc[1+i,1]*0.98),2)
else:
df.iloc[1+i,4] = df.iloc[i,4]
# Filling Column 'B'
df.iloc[1+i,5] = round(((df.iloc[1+i,1] + df.iloc[1+i,2])/2),2)
# Filling Column 'Counter'
if (df.iloc[1+i,5] > df.iloc[1+i,1]):
df.iloc[1+i,6] = df.iloc[1+i,0]
else:
df.iloc[1+i,6] = df.iloc[i,6]
df
Код ниже дает мне ошибку. где я попытался реализовать декоратор numba jit, чтобы ускорить исходный код Python.
#The code with numba jit which is throwing error is:
df = pd.DataFrame()
df['Serial']=[865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880]
df['Value']=[586,586.45,585.95,585.85,585.45,585.5,586,585.7,585.7,585.5,585.5,585.45,585.3,584,584,585]
df['Ref']=[586.35,586.1,586.01,586.44,586.04,585.91,585.47,585.99,585.35,585.27,585.32,584.86,585.36,584.18,583.53,585]
df['Base'] = [0,-1,1,1,1,1,-1,0,1,1,1,0,1,1,0,-1]
from numba import jit
@jit(nopython=True)
def Calcs(Serial,Value,Ref,Base):
n = Base.size
A = np.empty(n, dtype='f8')
B = np.empty(n, dtype='f8')
Counter = np.empty(n, dtype='f8')
A[0] = 0.0
B[0] = 0.0
Counter[0] = Serial[0]
for i in range(0,n-1):
# Filling Column 'A'
if (Ref[i+1] > Value[i+1]) & (B[i] > Value[i+1]) & (Base[i+1] > 0):
A[i+1] = round((Value[i+1]*1.02),2)
elif (Ref[i+1] < Value[i+1]) & (B[i] < Value[i+1]) & (Base[i+1] < 0):
A[i+1] = round((Value[i+1]*0.98),2)
else:
A[i+1] = A[i]
# Filling Column 'B'
B[i+1] = round(((Value[i+1] + Ref[i+1])/2),2)
# Filling Column 'Counter'
if (B[i+1] > Value[i+1]):
Counter[i+1] = Serial[i+1]
else:
Counter[i+1] = Counter[i]
List = [A,B,Counter]
return List
Serial = df['Serial'].values.astype(np.float64)
Value = df['Value'].values.astype(np.float64)
Ref = df['Ref'].values.astype(np.float64)
Base = df['Base'].values.astype(np.float64)
VCal = Calcs(Serial,Value,Ref,Base)
df['A'].values[:] = VCal[0].astype(object)
df['B'].values[:] = VCal[1].astype(object)
df['Counter'].values[:] = VCal[2].astype(object)
df
Я попытался изменить код в соответствии с руководством, предоставленным @Jérôme Richard для вопроса Как устранить цикл for в Pandas Dataframe при заполнении значений каждой строки столбца на основе нескольких операторов if, elif.
Но получаю ошибки и не могу исправить код. Ищу помощи от сообщества в исправлении и улучшении приведенного выше кода или в поиске еще лучшего кода для повышения скорости выполнения. Ожидаемый результат кода показан на рисунке ниже.
Вы можете использовать df['A'].values[:]
только в том случае, если столбец A
существует в фрейме данных. В противном случае вам нужно создать новый, возможно, с помощью df['A'] = ...
.
Более того, трюк с astype(object)
применим к строке, но не к числам. Действительно, столбцы фреймов данных на основе строк, по-видимому, не используют массив на основе строк Numpy, а массивы на основе объектов Numpy, содержащие строки CPython. Для чисел Pandas правильно использует числовые массивы. Преобразование чисел обратно в объект неэффективно. То же самое относится и к astype(np.float64)
: он не нужен, если время и так нормальное. Дело обстоит именно так. Если вы не уверены в типе ввода, вы можете разрешить их, поскольку они не очень дорогие.
Сама функция Numba в порядке (по крайней мере, с последней версией Numba). Обратите внимание, что вы можете указать подпись для скомпилируйте функцию с нетерпением. Эта функция также поможет вам быстрее обнаружить опечатки и сделать их немного более четкими. Недостатком является то, что это делает функцию менее универсальной, поскольку поддерживаются только определенные типы (хотя вы можете указать несколько подписей).
from numba import njit
@njit('List(float64[:])(float64[:], float64[:], float64[:], float64[:])')
def Calcs(Serial,Value,Ref,Base):
[...]
Serial = df['Serial'].values
Value = df['Value'].values
Ref = df['Ref'].values
Base = df['Base'].values
VCal = Calcs(Serial, Value, Ref, Base)
df['A'] = VCal[0]
df['B'] = VCal[1]
df['Counter'] = VCal[2]
Обратите внимание, что вы можете использовать флаг декоратора Numba fastmath=True
для ускорения вычислений, если вы уверены, что входной массив никогда не содержит пространственных значений, таких как NaN или Inf или -0, и вы не полагаетесь на ассоциативность FP-математики.
Спасибо, Жером Ришар. Я попробовал упомянутые изменения. Но получаю эту ошибку. TypingError: Ошибка в конвейере режима nopython (шаг: интерфейс nopython) Нет преобразования из списка (массив (float64, 1d, C)) <iv = None> в список (массив (float64, 1d, A)) <iv = None> для '$420return_value.5', определено как None
Во время: ввод назначения в <ipython-input-3-c8fe9f386d86> (37) Файл "<ipython-input-3-c8fe9f386d86>", строка 37: def Calcs(Serial,Value,Ref,Base): <источник опущен> Список = [A,B,Счетчик] вернуть список ^
Эта ошибка означает, что непрерывный массив, выделенный в функции Numba (имеющий тип array(float64, 1d, C)
), не может быть преобразован в несмежный из-за подтипизации списка. Я не вижу причин, по которым Numba не может преобразовать непрерывный массив в несмежный. Я думаю, что это ошибка вывода типа. Вы наверняка используете устаревшую реализацию Numba. Пожалуйста, проверьте версию с помощью nb.version_info.full
и обновите Numba, если у вас версия старше 0.54.1 (последняя версия — 0.55.1).
Обратите внимание, что простым обходным решением должно быть удаление List(float64[:])
в коде или использование вместо него List(float64[::1])
(чтобы сказать, что массивы непрерывны).
Сейчас работает Жером Ришар. Я внес изменения в подпись как @njit('List(float64[::1])(int64[::1], float64[::1], float64[::1], int64[::1])', fastmath=Истина). Спасибо большое.
Этот код дает список ошибок типа преобразования списка.
from numba import njit
df = pd.DataFrame()
df['Serial'] = [865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880]
df['Value'] = [586,586.45,585.95,585.85,585.45,585.5,586,585.7,585.7,585.5,585.5,585.45,585.3,584,584,585]
df['Ref'] = [586.35,586.1,586.01,586.44,586.04,585.91,585.47,585.99,585.35,585.27,585.32,584.86,585.36,584.18,583.53,585]
df['Base'] = [0,-1,1,1,1,1,-1,0,1,1,1,0,1,1,0,-1]
@njit('List(float64[:])(float64[:], float64[:], float64[:], float64[:])',fastmath=True)
def Calcs(Serial,Value,Ref,Base):
n = Base.size
A = np.empty(n)
B = np.empty(n)
Counter = np.empty(n)
A[0] = 0.0
B[0] = 0.0
Counter[0] = Serial[0]
for i in range(0,n-1):
# Filling Column 'A'
if (Ref[i+1] > Value[i+1]) & (B[i] > Value[i+1]) & (Base[i+1] > 0):
A[i+1] = round((Value[i+1]*1.02),2)
elif (Ref[i+1] < Value[i+1]) & (B[i] < Value[i+1]) & (Base[i+1] < 0):
A[i+1] = round((Value[i+1]*0.98),2)
else:
A[i+1] = A[i]
# Filling Column 'B'
B[i+1] = round(((Value[i+1] + Ref[i+1])/2),2)
# Filling Column 'Counter'
if (B[i+1] > Value[i+1]):
Counter[i+1] = Serial[i+1]
else:
Counter[i+1] = Counter[i]
List = [A,B,Counter]
return List
Serial = df['Serial'].values
Value = df['Value'].values
Ref = df['Ref'].values
Base = df['Base'].values
VCal = Calcs(Serial, Value, Ref, Base)
df['A'] = VCal[0]
df['B'] = VCal[1]
df['Counter'] = VCal[2]
df
Получение приведенной ниже ошибки.
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No conversion from list(array(float64, 1d, C))<iv=None> to
list(array(float64, 1d, A))<iv=None> for '$408return_value.5', defined at None
File "<ipython-input-9-3c9e0fe02b75>", line 33:
def Calcs(Serial,Value,Ref,Base):
<source elided>
List = [A,B,Counter]
return List
^
During: typing of assignment at <ipython-input-9-3c9e0fe02b75> (33)
File "<ipython-input-9-3c9e0fe02b75>", line 33:
def Calcs(Serial,Value,Ref,Base):
<source elided>
List = [A,B,Counter]
return List
^
Укажите ошибку (поскольку люди могут получить другую ошибку в отношении версии пакетов или даже отсутствие ошибки в некоторых случаях)