分段最小二乘算法,根本不理解这种动态编程概念

时间:2010-11-03 05:28:48

标签: python algorithm implementation

我一直在尝试用Python实现这个算法几天。我一直回到它,只是放弃和沮丧。我不知道最近发生了什么。我没有人要求或在任何地方寻求帮助所以我来这里。

PDF警告:http://www.cs.uiuc.edu/class/sp08/cs473/Lectures/lec10.pdf

我认为它没有明确解释,我当然不明白。

我对正在发生的事情的理解是:

我们有一组点(x1,y1),(x2,y2)..我们想找到一些最适合这些数据的线。我们可以有多条直线,这些线来自a和b的给定论坛(y = ax + b)。

现在算法从末尾(?)开始,并假设点p(x_i,y_i)是线段的一部分。然后笔记说最优解是'{p1,...的最优解。 。 。 pi-1}加上(最佳)直线{pi ,. 。 。 PN}”。这对我来说意味着我们转到点p(x_i,y_i)并向后移动并通过其余点找到另一个线段。现在,最佳解决方案是这些线段。

然后它需要一个我无法遵循的逻辑跳转,并说“假设最后一个点pn是从p_i开始的段的一部分。如果Opt(j)表示前j个点和e(j)的成本,k) 通过点j到k的最佳线的误差然后Opt(n)= e(i,n)+ C + Opt(i - 1)“

然后有算法的伪代码,我不明白。我知道我们想迭代点列表并找到最小化OPT(n)公式的点,但我不遵循它。这让我觉得很蠢。

我知道这个问题是一个痛苦的问题,并不容易回答,但我只是在寻找一些指导来理解这个算法。我为PDF道歉,但我没有更简洁的方法将重要信息传达给读者。

感谢您的时间和阅读本文,我很感激。

4 个答案:

答案 0 :(得分:3)

棘手的部分,即动态编程部分,是

部分
for j = 1 to n
    M[j] = min_(1=<i=<j) ( e(i,j) + C + M[i-1])

其中M[0] = 0之前完成,n是数据点的总数。此外,下划线表示后面的括号中的部分应该是下标。教授很可能使用OPT而不是M,这可以在其他一些大学关于此的讲座中完成,你可以在网上找到(看起来几乎相同)。现在,如果您查看上面的代码块和讲座中的代码块,您会发现有所不同。我使用了M[i-1],而您的教授使用了M[j-1]。这是教授伪代码中的一个错字。您甚至可以回顾之前的幻灯片,看看他在那里的错误功能中是否正确。

基本上,对于每个j,你会找到点i向j绘制一条线,使得它的误差加上添加这条额外线(C)的成本加上使所有线段增加的成本对i(已经被最佳选择)最小化。

另外,请记住e(i,i) = 0以及e(i,i+1),因为在一个点上插入一行不会产生任何错误,也不会产生两点。

答案 1 :(得分:3)

最小二乘问题要求找到一条最适合给定点的单行,并且有一个很好的封闭形式解决方案。该解决方案用作解决分段最小二乘问题的基元。

在分段最小二乘问题中,我们可以有任意数量的段来适应给定的点,我们必须为每个使用的新段支付费用。如果使用新段的成本为0,我们可以通过在每个点上单独一行来完美地拟合所有点。

现在假设我们正在尝试找到最适合n个给定点的一组段。如果我们知道n-1子问题的最佳解决方案:最适合第一点,最适合前2点,......,最适合前n-1点,那么我们可以计算原始问题的最佳解决方案n点如下:

第n个点位于单个段上,并且该段从某个较早的点i开始,对于某些i = 1,2,...,n。我们已经解决了所有较小的子问题,即少于n个点,因此我们可以找到最适合n点的最佳点:

最适合第一个i-1分(已计算)+的成本 单线成本最适合点i到n(使用最小二乘问题)+ 使用新细分的费用

最小化上述数量的i的值为我们提供了解决方案:使用最适合子问题i-1和段到点i到n。

如果您需要更多帮助,我已经写了算法的解释并在此处提供了C ++实现:http://kartikkukreja.wordpress.com/2013/10/21/segmented-least-squares-problem/

答案 2 :(得分:1)

从第1点开始,直到点j的最佳解决方案必须在最后一个线段中包含新的端点j,因此问题变为我必须放置最后一个分割的位置以最小化此成本最后一个线段?

幸运的是,成本是根据您尝试解决的同一问题的子问题来计算的,幸运的是,当您转移到下一个点j时,您已经解决了这些较小的子问题。因此,在新的点j,您试图在点1和点j之间找到最佳点i,以拆分包含j的新线段,并最小化成本:optimal_cost_up_to(i)+ cost_of_split + cost_of_lsq_fit(i + 1 ,J)。现在令人困惑的部分是,在任何时候你可能看起来只是找到一个分裂,但实际上所有先前的分裂都是由optimal_cost_up_to(i)确定的,并且因为你已经计算了所有这些点的最优成本导致j,然后你只需要记住答案,这样算法就不必在每次推进一个点时重新计算这些成本。

在python中,我可能会使用字典来存储结果,但对于这种动态编程算法,数组可能会更好......

反正...

    def optimalSolution(points,split_cost)
        solutions = {0:{'cost':0,'splits':[]}}
        for j in range(1,len(points)):
            best_split = None
            best_cost = lsqFitCost(points,0,j)
            for i in range(0,j):
                cost = solutions[i]['cost'] + split_cost + lsqFitCost(points,i+1,j)
                if cost < best_cost:
                   best_cost = cost
                   best_split = i
            if best_split != None:
                solution[j] = {'cost':best_cost,'splits':solution[best_split]['splits']+[best_split]}
            else:
                solution[j] = {'cost':best_cost,'splits':[]}
        return solutions

它不漂亮,我还没有检查过(可能有一个错误涉及没有拆分是最好的成本的情况),但希望它能帮助你走上正确的道路?请注意,lsqFitCost必须在每次迭代时做很多工作,但对于像这样的最小二乘线,你可以通过保持计算中使用的运行总和来减少这个成本...你应该谷歌最小二乘线拟合更多信息。这可能会使lsqFitCost保持不变,因此总时间将为O(N ^ 2)。

答案 3 :(得分:0)

动态编程的基本前提是递归地优化(降低'成本'或在这种情况下,错误)问题,同时存储子问题的成本,因此它们不会被重新计算(这称为memoization)。

有点晚了,所以我不会太详细,但看起来你最关心的部分是核心DP本身。由于“分段”质量,这里需要DP。正如您的PDF所示,通过最小二乘法找到最合适的线很简单,不需要DP。

  

选项(n) - e(i,n)+ C +选项(i-1)---我们的成本函数,其中
  C是新线段的固定成本(没有它,问题是微不足道的,我们只会为每两个点创建新的线段)
  e(i,n)是具有一个段(非递归)的点i到n的误差   Opt(i-1)是从第一个点到第(i-1)个递归的最低成本

现在算法

  

确保点列表按x值排序   M [0] = 0 ---自我解释
  对于所有对(i,j),其中i <1。 j:找到e(i,j)----(这将需要嵌套for / foreach循环,或者理解类型的结构。将这些值存储在2D数组中!)
  对于(j = 1..n):    M [j] = min([Opt(j)for i in range(1,j)]

所以基本上,找到任意两个可能点之间的单线成本,存储在e
中 找到最小为j的成本,j在1和n之间。沿途的值将有助于以后的计算,所以存储它们!请注意,i也是Opt的参数。 M [n]是总优化成本。

问题 - 如何确定细分发生的位置?你怎么能用这个和M来判断整个线段的集合?

希望这有帮助!