【问题标题】:Optimizing ranges in R在 R 中优化范围
【发布时间】:2011-12-13 11:13:49
【问题描述】:

我有以下问题,不知道如何在 R 中编码:

具有两列的数据框df:第一列是一组有序的数字df$ind,第二列是一组高度随机的数字df$ret

我想在df$ret 中找到两个不重叠的范围,并优化第一个范围内的数字之和必须为正数且第二个范围内的数字之和为负数的条件。之后,我想拥有各自范围的 2x2 df$ind-values。

我想到了两种可能性(我不知道如何在 R 中对其中任何一种进行编程):

  1. Monte Carlo 选择 2x2 位置,计算总和并与迄今为止的最佳解决方案进行比较。
  2. 尝试所有可能的范围并采取最佳解决方案(考虑到值的数量,这似乎在计算上是可行的)。

您能否给我一些提示,如何在 R 中实现这一点,或者是否有用于此类优化的包(R 中似乎有一个包用于所有内容;-)

更新:
您将有 4 个值:ikmndf$ret[i:k]df$ret[m:n]i k m n。

优化是(伪代码):

最大:abs(sum(范围(i:k)))+abs(sum(范围(m:n)))


条件:

sum(range(i:k)) > 0 和 sum(range(m:n))

【问题讨论】:

  • 优化是您可以比较数字并选择最高或最低的。假设我们找到两个解决方案,即两个范围对,满足您的条件。不清楚你更喜欢哪一个。
  • vonjd,好的,现在很清楚了。如果您更新问题会很棒,我认为这将有助于获得答案。
  • 观察到你可能假设 m=k+1 是一个很好的简化。如果不是,考虑元素 k+1 到 m-1 的总和:如果总和为正,则将这些元素包括在第一个范围内;如果是否定的,则将它们包含在第二个中;如果为零,则将它们包含在其中之一中。目标永远不会减少,QED。话虽如此,我投票结束这个问题,因为虽然它很有趣,但它在 CV 上是题外话。
  • @whuber:好主意!我想知道为什么在我的测试中这两个范围总是紧挨着的......很好地提醒我在编码之前总是三思而后行。
  • @Aaron 当您根据数据的累积总和重新提出问题时,像我所做的那样的观察变得显而易见。 (你试图找到一个上升然后下降,并且你正在优化总上升加上总下降。)这(我希望)清楚地说明了如何加速算法。

标签: r optimization


【解决方案1】:

这是一种蛮力方法。对于小型数据集,它应该可以正常工作;在我的系统上,我使用 100 号进行了测试,大约为 0.5 秒。为了提高速度,应在检查所有可能的最大/最小对之前检查最佳的最大和最小重叠。

getbest <- function(x) {
  # get the sums of all possible ranges
  n <- length(x)
  m <- as.data.frame(t(combn(n, 2)))
  names(m) <- c("lo","hi")
  m$sum <- sapply(1:nrow(m), function(i) {
    sum(x[m$lo[i]:m$hi[i]])
  })
  # then get the ranges of positive and negative sums that don't overlap
  neg <- m[m$sum<0,]
  pos <- m[m$sum>0,]
  use <- expand.grid(neg=1:nrow(neg), pos=1:nrow(pos))
  use <- use[(neg$hi[use$neg] < pos$lo[use$pos]) | 
                  (neg$lo[use$neg] > pos$hi[use$pos]),]
  # finally get the absolute value for all ranges that don't overlap,
  # and choose the largest
  abs <- pos$sum[use$pos] - neg$sum[use$neg]
  use <- use[which.max(abs),]
  as.matrix(rbind(positive=pos[use$pos,], negative=neg[use$neg,]))
}

如下使用;它返回范围的实际索引,因此如果所需的索引 df$ind1:n 不同,只需使用此输出来获取所需的值。

x <- rnorm(100)
getbest(x)

【讨论】:

  • 哇,真快!谢谢,我测试了几次,它似乎工作正常!我现在将在我的真实世界数据上进行尝试。
  • 我试图理解代码的逻辑。我可以请您添加一些额外的解释或一些 cmets 吗?那将非常有帮助!再次感谢您!
  • 我添加了一些基本的 cmets,但更好的算法是遵循@whuber 的建议。
  • 刚刚注意到上面的算法只允许宽度为 2 或更大的范围;也就是i &lt; km &lt; n,和原帖一样;但是,在我看来,i &lt;= km &lt;= n 似乎是需要的,这样一个范围只能包含一个数字。
  • 是的,但这是不可取的,因为数据非常嘈杂。一个异常值将构成整个范围 - 不好。最好似乎是定义一些最小值的可能性。长度。
【解决方案2】:

这个问题是 Jon Bentleys 著名的“Programming Pearls”第 7 栏的主题。解决方案是运行时间为 O(n) 的算法,其中 n 是向量 x 的长度。

R 实现可以在 3 秒内解决数百万个元素的向量:

x <- rnorm(1e6)
system.time(m <- maxsub(x))

如果您也想要负数,请调用 maxsub(-x)。更改代码以使函数返回索引很容易。这两个范围不能重叠,但一个可以是另一个的一部分。

maxsub <- function(x) {
    if (!is.numeric(x))
        stop("Argument 'x' must be a numeric vector.")

    m1 <- m2 <- 0.0
    for (i in 1:length(x)) {
        m2 <- max(m2 + x[i], 0.0)
        m1 <- max(m1, m2)
    }
    return(m1)
}

尽管代码看起来很简单,但正如 Bentley 报道的那样,直到有人想出这个解决方案还是花了很长时间。尚未找到二维(或更高)维情况的相应算法。

更新:这是一个也返回索引的版本。看起来很复杂,其实不然。它只是跟踪上述两个步骤中的每个步骤中的索引。

maxsub <- function(x, inds = FALSE) {
    if (!is.numeric(x))
        stop("Argument 'x' must be a numeric vector.")
    n <- length(x)

    if (!inds) {
        m1 <- m2 <- 0.0
        for (i in 1:n) {
            m2 <- max(m2 + x[i], 0.0)
            m1 <- max(m1, m2)
        }
        return(m1)

    } else {
        m1 <- m2 <- 0
        p1 <- p2 <- 0
        q1 <- q2 <- 1

        for (i in 1:n) {
            if (m2 > -x[i]) {
                m2 <- m2 + x[i]
                q2 <- i
                if (m2 > m1) {
                    m1 <- m2
                    p1 <- q1; p2 <- q2
                }
            } else {
                m2 <- 0
                q1 <- q2 <- i+1
            }
        }

        return(list(sum = m1, inds = c(p1, p2)))
    }
}

绑定到 R 包的 Fortran 版本确实可以在 0.015 秒内解决一百万个元素。

【讨论】:

  • 感谢您的参考。关于如何将一个范围包含在另一个范围中的任何想法?
  • @Hans:我不得不说我还没有完全理解底层逻辑 - 你能否对返回索引进行必要的修改,我希望这会让事情变得更清楚。感谢您分享这个明显高效且优雅的算法!
  • ...顺便说一句:我认为这是第 8 列,而不是第 7 列。
  • @vonjd:我添加了一个返回索引的版本。要理解算法,最好看一下开头的四行。或者阅读第 7 栏“算法设计技巧”(在我的“编程珍珠”版本中)或第 8 栏(您的版本?)——绝对值得。
猜你喜欢
  • 2018-05-22
  • 1970-01-01
  • 2011-07-30
  • 2014-07-24
  • 1970-01-01
  • 2016-06-04
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
相关资源
最近更新 更多