执行天际线查询或有效前沿

时间:2012-02-02 02:34:03

标签: r select dataframe

我知道必须有一个简单的答案,但不知何故我似乎无法找到它......

我有一个包含2个数字列的数据框。 我想从中删除具有属性的行,数据框中至少存在另一行,其中两列值都大于此行中的列值。

所以,如果我有

    Col1 Col2  
1     2    3  
2     4    7  
3     5    6  

我想删除第一行,因为第二行符合属性并且只保留第2行和第3行。

非常感谢!

6 个答案:

答案 0 :(得分:21)

这个问题被数据库管理员称为“天际线查询”(他们可能有其他算法)和经济学家的“有效前沿”。 绘制数据可以清楚地表明我们在寻找什么。

n <- 40
d <- data.frame(
  x = rnorm(n),
  y = rnorm(n)
)
# We want the "extreme" points in the following plot
par(mar=c(1,1,1,1))
plot(d, axes=FALSE, xlab="", ylab="")
for(i in 1:n) {
  polygon( c(-10,d$x[i],d$x[i],-10), c(-10,-10,d$y[i],d$y[i]), 
  col=rgb(.9,.9,.9,.2))
}

算法如下:沿第一个坐标对点进行排序, 保持每次观察,除非它比最后保留的更差。

d <- d[ order(d$x, decreasing=TRUE), ]
result <- d[1,]
for(i in seq_len(nrow(d))[-1] ) {
  if( d$y[i] > result$y[nrow(result)] ) {
    result <- rbind(result, d[i,])  # inefficient
  } 
}
points(result, cex=3, pch=15)

Skyline

答案 1 :(得分:9)

编辑(2015-03-02):要获得更有效的解决方案,请参阅Patrick Roocks的rPref,“数据库首选项和Skyline计算”软件包,(也已链接)在下面的回答中)。为了表明它找到了与我的代码相同的解决方案,我在这里附上了一个使用它的例子到我的原始答案。


重申Vincent Zoonekynd的启发性回应,这是一个完全矢量化的算法,可能效率更高:

set.seed(100)
d <- data.frame(x = rnorm(100), y = rnorm(100))

D   <- d[order(d$x, d$y, decreasing=TRUE), ]
res <- D[which(!duplicated(cummax(D$y))), ]
#             x         y
# 64  2.5819589 0.7946803
# 20  2.3102968 1.6151907
# 95 -0.5302965 1.8952759
# 80 -2.0744048 2.1686003


# And then, if you would prefer the rows to be in 
# their original order, just do:
d[sort(as.numeric(rownames(res))), ]
#            x         y
# 20  2.3102968 1.6151907
# 64  2.5819589 0.7946803
# 80 -2.0744048 2.1686003
# 95 -0.5302965 1.8952759

或者,使用 rPref 包:

library(rPref)
psel(d, high(x) | high(y))
#             x         y
# 20  2.3102968 1.6151907
# 64  2.5819589 0.7946803
# 80 -2.0744048 2.1686003
# 95 -0.5302965 1.8952759

答案 2 :(得分:5)

这是一个sqldf解决方案,其中DF是数据的数据框:

library(sqldf)
sqldf("select * from DF a
 where not exists (
   select * from DF b
   where b.Col1 >= a.Col1 and b.Col2 >  a.Col2  
      or b.Col1 >  a.Col1 and b.Col2 >= a.Col2
 )"
)

答案 3 :(得分:4)

这个问题已经很老了,但同时还有一个新的解决方案。我希望在这里做一些自我推销是可以的:我开发了一个包rPref,它可以根据C ++算法进行有效的Skyline计算。使用已安装的rPref包,可以通过问题完成查询(假设df是数据集的名称):

library(rPref)
psel(df, high(Col1) | high(Col2))

这只删除那些元组,其中一些其他元组在两个维度上都更好。

如果要求另一个元组在一个维度上严格更好(在另一个维度中更好或相等),请改用high(Col1) * high(Col2)

答案 4 :(得分:2)

在一行中:

d <- matrix(c(2, 3, 4, 7, 5, 6), nrow=3, byrow=TRUE)
d[!apply(d,1,max)<max(apply(d,1,min)),]

     [,1] [,2]
[1,]    4    7
[2,]    5    6

编辑:根据您在jbaums的响应中的精确度,这里是如何分别检查两个列。

d <- matrix(c(2, 3, 3, 7, 5, 6, 4, 8), nrow=4, byrow=TRUE)
d[apply(d,1,min)>min(apply(d,1,max)) ,]

     [,1] [,2]
[1,]    5    6
[2,]    4    8

答案 5 :(得分:0)

d <- matrix(c(2, 3, 4, 7, 5, 6), nrow=3, byrow=TRUE)
d2 <- sapply(d[, 1], function(x) x < d[, 1]) & 
      sapply(d[, 2], function(x) x < d[, 2])
d2 <- apply(d2, 2, any)
result <- d[!d2, ]