如何将自定义equality_check函数传递到 perfplot 中

How to pass a custom equality_check function into perfplot

提问人:cottontail 提问时间:11/24/2022 更新时间:11/24/2022 访问量:149

问:

我正在使用 perfplot 库来比较三个函数的性能,并且 .这些函数应该返回相同的值,因此我想进行相等性检查。但是,我可以在互联网上找到所有其他 perfplot 示例或作为相等检查器,但这些不适用于我的特定情况。f1f2f3pd.DataFrame.equalsnp.allclose

例如,如果函数返回不同长度的 numpy 数组列表,则不起作用。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
)

如何传递与上述函数不同的函数?

Python 相等 性能

评论


答:

0赞 cottontail 11/24/2022 #1

如果我们检查源代码,相等性检查的工作方式是将传递给的第一个函数的输出作为引用,并将其与循环中传递给的后续函数的输出进行比较。kernelskernels

出于某种原因,相等性检查会有所不同,具体取决于 中的第一个函数是否返回元组。kernels

如果 中的第一个函数不返回元组,则它只是调用传递给参数的函数来执行检查。相等性检查函数接受两个参数,可以执行任何操作。例如,它只能检查长度是否相等并称其为一天(即将以下 lambda 传递给 : )。kernelsequality_checkequality_checklambda 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"
                    )