寻找重复代码的抽象:Bootstrap分析

时间:2017-01-29 10:01:59

标签: python numpy refactoring

简介

在我的Python代码中,我总是使用一种模式进行分析 数值数据。所有实现都显得过于冗余或非常繁琐 只是不要与NumPy功能很好地配合。我想找到一个更好的方法 抽象这种模式。

问题/当前状态

统计错误传播的方法是引导方法。它的工作原理 使用稍微不同的输入多次运行相同的分析并查看 最终结果的分布。

要计算ams_phys的实际值,我有以下等式:

ams_phys = (amk_phys**2 - 0.5 * ampi_phys**2) / aB - amcr

进入该等式的所有值都存在相关的统计误差 用它。这些值也可以从其他方程计算出来。例如 amk_phys是根据这个等式计算的,其中两个数字也有 不确定性:

amk_phys_dist = mk_phys / a_inv

mk_phys的值在论文中给出为(494.2±0.3)。我现在做的是 参数化bootstrap 并从高斯分布生成R个样本 平均值为494.2,标准差为0.3。这就是我存储的内容 mk_phys_dist

mk_phys_dist = bootstrap.make_dist(494.2, 0.3, R)

对于a_inv也是如此,其中也引用了错误 文献。然后将上面的等式转换为列表理解以产生 一个新的发行版:

amk_phys_dist = [mk_phys / a_inv
                 for a_inv, mk_phys in zip(a_inv_dist, mk_phys_dist)]

然后第一个等式也被转换为列表理解:

ams_phys_dist = [
    (amk_phys**2 - 0.5 * ampi_phys**2) / aB - amcr
    for ampi_phys, amk_phys, aB, amcr
    in zip(ampi_phys_dist, amk_phys_dist, aB_dist, amcr_dist)]

为了得到(值±误差)的最终结果,我接受平均值和 这种数字分布的标准差:

ams_phys_val, ams_phys_avg, ams_phys_err \
        = bootstrap.average_and_std_arrays(ams_phys_dist)

实际值应该用实际值来计算, 不是这个bootstrap发行版的意思。在我复制代码之前 为此,现在我在_dist的第0位有原始值 阵列。这些数组现在包含1 + R个元素和 bootstrap.average_and_std_arrays函数将该元素分开。

对于我可能想引用的每个数字,都会出现这种情况 写作。我对写作感到恼火并为它创建了一个片段:

$1_val, $1_avg, $1_err = bootstrap.average_and_std_arrays($1_dist)

对代码片段的需求强烈告诉我,我需要进行一些重构。 列表推导也总是具有以下模式:

foo_dist = [ ... bar ...
            for bar in bar_dist]

在那里写三次bar感觉不好。

班级方法

我试图将这些_dist内容设为Boot类,这样我就不会这样做 写ampi_distampi_val,但可以只使用ampi.val 显式调用此average_and_std_arrays函数并键入一堆 它的名字。

class Boot(object):
    def __init__(self, dist):
        self.dist = dist

    def __str__(self):
        return str(self.dist)

    @property
    def cen(self):
        return self.dist[0]

    @property
    def val(self):
        x = np.array(self.dist)
        return np.mean(x[1:,], axis=0)

    @property
    def err(self):
        x = np.array(self.dist)
        return np.std(x[1:,], axis=0)

然而,这仍然没有解决列表推导的问题。一世 我担心我还要在那里重复三次。我可以做到 Boot对象继承自list,因此我至少可以像写一样 这个(没有_dist):

bar = Boot([... foo ... for foo in foo])

魔术方法

理想情况下,所有这些列表理解都会消失,以至于我可以 写

bar = ... foo ...

其中点表示一些非平凡的操作。那些可以是简单的算术 如上所述,但也可以是函数调用,而不是 支持使用多个值调用(如NumPy函数支持)。

例如,需要多次调用scipy.optimize.curve_fit函数:

popt_dist = [op.curve_fit(linear, mpi, diff)[0]
             for mpi, diff in zip(mpi_dist, diff_dist)]

必须为此编写一个包装器,因为它不会自动遍历数组列表。

问题

您是否看到了一种方法来抽象运行每个转换的过程 1 + R组数据?我想摆脱那些模式和巨大的 每个命名空间中的变量数量(_dist_val_avg,...)就像这样 使它传递给相当乏味的功能。

我需要在... foo ...部分获得很多自由 调用任意函数。

0 个答案:

没有答案