Я работаю с библиотекой perfplot, чтобы сравнить производительность трех функций f1
, f2
и f3
. Предполагается, что функции возвращают одни и те же значения, поэтому я хочу выполнить проверку на равенство. Однако все другие примеры перфплотов, которые я могу найти в Интернете, используют pd.DataFrame.equals
или np.allclose
в качестве проверки равенства, но они не работают для моего конкретного случая.
Например, np.allclose
не будет работать, если функции возвращают список пустых массивов разной длины.
import perfplot
import numpy as np
def f1(rng):
return [np.array(range(i)) for i in rng]
def f2(rng):
return [np.array(list(rng)[:i]) for i in range(len(rng))]
def f3(rng):
return [np.array([*range(i)]) for i in rng]
perfplot.show(
kernels=[f1, f2, f3],
n_range=[10**k for k in range(4)],
setup=lambda n: range(n),
equality_check=np.allclose # <-- doesn't work; neither does pd.DataFrame.equals
)
Как мне передать функцию, отличную от вышеупомянутых функций?
Если мы проверим исходный код , проверка на равенство работает следующим образом: она берет выходные данные первой функции, переданной kernels
, в качестве эталона, и сравнивает их с выходными данными последующих функций, переданных kernels
, в цикле.
По какой-то причине проверка на равенство различается в зависимости от того, возвращает ли первая функция в kernels
кортеж или нет.
Если первая функция в kernels
не возвращает кортеж, она просто вызывает функцию, переданную аргументу equality_check
, для выполнения проверки. Функция проверки на равенство принимает два аргумента и может делать что угодно. Например, он может только проверить, равны ли длины, и назвать это днем (т.е. передать следующую лямбду в equality_check
: lambda x,y: len(x) == len(y)
).
Например, в вопросе работает функция, которая перебирает пары элементов и проверяет неравенство.
def equality_check(x, y):
for i, j in zip(x, y):
if not np.allclose(i, j):
return False
return True
perfplot.show(
kernels=[f1, f2, f3],
n_range=[10**k for k in range(4)],
setup=lambda n: range(n),
equality_check=equality_check
)
На самом деле, all()
тоже работает.
perfplot.show(
kernels=[f1, f2, f3],
n_range=[10**k for k in range(4)],
setup=lambda n: range(1, n+1),
equality_check=lambda x,y: all([x,y])
)
Следующий код, скопированный из исходного кода, представляет собой фрагмент, реализующий проверку на равенство:
for k, kernel in enumerate(self.kernels):
val = kernel(*data)
if self.equality_check:
if k == 0:
reference = val
else:
try:
if isinstance(reference, tuple):
assert isinstance(val, tuple)
assert len(reference) == len(val)
is_equal = True
for r, v in zip(reference, val):
if not self.equality_check(r, v):
is_equal = False
break
else:
is_equal = self.equality_check(reference, val)
except TypeError:
raise PerfplotError(
"Error in equality_check. "
+ "Try setting equality_check=None."
)
else:
if not is_equal:
raise PerfplotError(
"Equality check failure.\n"
+ f"{self.labels[0]}:\n"
+ f"{reference}:\n\n"
+ f"{self.labels[k]}:\n"
+ f"{val}:\n"
)