[英]How to subset and find time difference between two data points using bike station data
[英]How to find the maximal and minimal strictly positive difference between two subset sums of a vector?
我搜索了这个,但找不到任何似乎匹配的东西; 如果有人可以帮助或指出我正确的方向,那就太好了。
假设您有一个数值向量h = c(-1,-2,3,5,6,9)
(我使用的是 R)。
您对该向量的 3 个元素进行了 2 个不同的选择。 您取每个选择的总和,然后取两个总和之间的差。
例如,一个选择可以是c(-1,3,5)
--> 总和是 7; 另一个c(-2,3,9)
--> 总和为 10; 差异是 10-7 = 3。
你要知道:
对于像这样的小向量,您可以使用蛮力,获得两个总和之间所有可能的差异,然后查找所需的值。
h = c(-1,-2,3,5,6,9)
N <- length(h)
n <- 3
vs <- expand.grid(rep(list(0:1),2*N))
vs["np1"] <- rowSums(vs[,1:N])
vs["np2"] <- rowSums(vs[,(N+1):(2*N)])
vs <- vs[(vs$np1 == n) & (vs$np2 == n),]
vs["hSum1"] <- apply(vs,1,function(x) sum(h*x[1:N]))
vs["hSum2"] <- apply(vs,1,function(x) sum(h*x[(N+1):(2*N)]))
vs["hdiff"] <- vs$hSum2-vs$hSum1
max(vs$hdiff)
#[1] 20
min(vs[vs$hdiff > 0,"hdiff"])
#[1] 1
显然,这对于较大的向量是不可能的。
我发现通过简单地对h
(升序)进行排序并取其最后 3 个和前 3 个元素之间的差异可以找到最大的差异:
sum(sort(h)[(N-n+1):(N)]-sort(h)[1:n])
#[1] 20
但是,我无法找出最小正差异的解决方案。
我尝试了线性规划,但我找不到将严格不等式强加于差异的技巧,这(我认为)是避免获得 0 作为解决方案所必需的。
从这个意义上说, 这篇文章在概念上看起来很接近,但我无法理解它,因为我看不到该方法的来源,并且当我在没有试图理解它的情况下应用它时,它不起作用.
有任何想法吗?
谢谢!
编辑- 找到最小正差的可能 LP 解决方案
通过迭代。
让Dmin
成为所寻求的差异。 我首先找到Dmin
的上限,作为h
唯一元素之间的最小成对差异:
h <- c(2.1,1,-0.5,0,1.7,2.3)
N <- length(h)
n <- 3
min.hdiff <- min(diff(sort(unique(h))))
UB <- min.hdiff
UB
#[1] 0.2
下限可以设置为 0:
LB <- 0
在这种情况下,很明显UB
不是Dmin
; 可以通过蛮力检查Dmin
为 0.1。
为了通过 LP 重现它,我首先定义了一个函数来查找LB 和 UB 之间包含的最大(而不是最小)正差:
obj <- c(h,-h)
constr.n1 <- c(rep(1,N),rep(0,N))
constr.n2 <- c(rep(0,N),rep(1,N))
dir.n <- "=="
rhs.n <- n
constr.D <- c(h,-h)
dir.D1 <- ">="
rhs.D1 <- LB
dir.D2 <- "<="
rhs.D2 <- UB
mat <- rbind(constr.n1,constr.n2,constr.D,constr.D)
dir <- c(dir.n,dir.n,dir.D1,dir.D2)
rhs <- c(rhs.n,rhs.n,rhs.D1,rhs.D2)
N.rhs <- length(rhs)
require(Rsymphony)
DS.feas <- function(LB,UB) {
rhs[c(N.rhs-1,N.rhs)] <- c(LB,UB)
LP.sol <- Rsymphony_solve_LP(obj,mat,dir,rhs,types="B",max=T)
if ((LP.sol$status == 0) & (LP.sol$objval > 0)) {return(list(1,LP.sol$solution,LP.sol$objval))} else {return(list(0,NULL,LP.sol$objval))}
}
然后我检查初始 [LB,UB] 是否可行:
LB.feas <- DS.feas(LB,UB)
LB.feas
#[[1]]
#[1] 1
#
#[[2]]
# [1] 0 1 0 1 0 1 1 1 0 1 0 0
#
#[[3]]
#[1] 0.2
由于当前[LB,UB]
是可行的,在下一次迭代中,我测试LB
和UB
( MB
) 之间的中点作为新的推定UB
:
MB = (LB+UB)/2
MB
#[1] 0.1
MB.feas = DS.feas(LB,MB)
MB.feas
#[[1]]
#[1] 1
#
#[[2]]
# [1] 0 1 0 1 1 0 1 1 1 0 0 0
#
#[[3]]
#[1] 0.1
可行的。 所以我将UB
设置为MB
并测试新的、较低(但仍然为正)的中点:
UB = MB
MB = (LB+UB)/2
MB
[1] 0.05
MB.feas = DS.feas(LB,MB)
#MB.feas
#[[1]]
#[1] 0
#
#[[2]]
#NULL
#
#[[3]]
#[1] 0
不可行。 所以Dmin
必须在当前MB
和UB
。 我将LB
设置为MB
并运行下一次迭代。
依此类推,直到达到收敛。
我在各种载体上对此进行了测试。
它似乎有效; 只是,对于N = 20
,它已经变得非常慢了。
如果有人可以建议如何更好地做到这一点......
我不知道 r,但我确定您可以制定与此 python 解决方案相同的问题:
from pulp import *
vals = [-1,-2,3,5,6,9]
r = range(0, len(vals))
#group1[i] = 1 if we use vals[i] in first group
group1 = LpVariable.dicts('group1', r, cat='Binary')
group2 = LpVariable.dicts('group2', r, cat='Binary')
#repeats[i] = 1 if we allow to use vals[i] in both groups
repeats = LpVariable.dicts('repeats', r, cat='Binary')
prob = LpProblem('test', LpMinimize)
sum1 = lpSum([group1[i] * vals[i] for i in r])
sum2 = lpSum([group2[i] * vals[i] for i in r])
#objective
prob += sum1 - sum2
#make group1 be highest sum to prevent negative solutions
prob += sum1 >= sum2
#make each group have 3 items
prob += lpSum([group1[i] for i in r]) == 3
prob += lpSum([group2[i] for i in r]) == 3
#dont allow choosing same number for both groups if we are not allowing repeat
for i in r:
prob += group1[i] + group2[i] <= repeats[i] + 1
#only allow up to 2 repeats (thus preventing same solution repeating 3)
prob += lpSum([repeats[i] for i in r]) <= 2
prob.solve()
print([vals[x] for x in r if group1[x].value()], [vals[x] for x in r if group2[x].value()])
编辑:只需重新阅读您的问题,似乎您不想允许解决方案 0。在这种情况下,它更容易,可以删除与重复相关的所有内容,只需将第一个限制更改为:
#avoid solution 0
prob += sum1 - sum2 >= 1
最小的区别其实是分区问题https://en.wikipedia.org/wiki/Partition_problem
最大的差异是一个子集中的所有负数和另一个子集中的正数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.