2012-02-02 26 views
10

我知道必須有一個簡單的答案,這但不知何故,我似乎無法找到它的...實施輪廓查詢或有效邊界

我有2個數字列的數據幀。 我想從中刪除具有該屬性的行,在數據框中至少存在另一行,並且列值都大於此行中的行值。

所以,如果我有

Col1 Col2 
1  2 3 
2  4 7 
3  5 6 

我想刪除的第一行,因爲第二個滿足的財產,只保留行2和3

非常感謝!

+0

我無法設置編輯,因爲它只有空格,但是您的表格可以使用代碼格式:在每行之前放置一個額外的4個空格,並且它將以與您使用的格式相同的格式出現它更具可讀性。 – Jeff 2012-02-02 02:41:49

+0

謝謝傑夫,我試圖找出如何做到這一點,但我失敗了。 – user1184143 2012-02-02 04:01:49

回答

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

+0

是的,這正是我想要做的,但我認爲這樣做「C」的方式是不合適的,謝謝一堆! – user1184143 2012-02-02 04:03:43

+0

好的情節和見解。 – 2012-02-02 14:59:42

+0

+1,謝謝你的好評。我特別感謝你與天際線查詢建立連接,然後包括一個情節,以說明爲什麼它有這個名字!我已經在下面添加了一個答案,靈感來自你的,它用更多的R-ish矢量化構造替換了for()'循環。 – 2012-02-02 17:07:26

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, ] 
+0

嗯,我並不完全理解這一點,但我的感覺是,它不會分別查看每一列。舉例來說,如果您的行>(d,c)(c(2,3,3,7,5,6,4,8),nrow = 4,byrow = TRUE)row(3,7)也應該被移除,因爲4,8)在兩列中都較大。感謝您的回覆。 – user1184143 2012-02-02 04:14:39

+0

對,我誤解了你的要求。我讀它的意思是「如果B行中的每個數字大於A行中的每個數字,排除行A」。因爲4和8每個都不大於3和7(即4不大於7),所以不符合標準,並且不排除該行。現在我明白你對B行的值是否大於A行相應列的值感興趣。我已經編輯了答案來糾正它(我認爲)。 – jbaums 2012-02-02 04:49:51

+0

(現在應該排除那些行存在的每一列中有較大值的行,我相信Vincent的解決方案將排除另一行存在的行在每列中具有較大*或相等*值的行,儘管這可能確實是您打算寫在你的問題..?) – jbaums 2012-02-02 06:26:55

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 
+0

但是,我需要獨立對待每個列,例如,如果我有d < - 矩陣(c(1,8,7,2),nrow = 2,byrow = TRUE ),因爲第一行在第二列中具有最高值而第二行在第一列中具有最高值,因此在兩個**列中都沒有其他行具有較高值,所以應該保留兩行。 – user1184143 2012-02-04 01:33:34

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 
)" 
) 
9

編輯(2015年3月2日):對於更有效的解決方案,請參閱帕特里克Roocks' rPref,用於「數據庫首選項和天際線計算」的包(也在以下答案中鏈接)。爲了表明它找到與我的代碼相同的解決方案,我在這裏附加了一個使用它的例子。


Riffing關文森特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 
+0

非常優雅!謝謝。 – user1184143 2012-02-04 01:43:58

4

這個問題很舊,但同時有一個新的解決方案。我希望在這裏做一些自我推銷是可以的:我開發了一個包rPref,它由於C++算法而進行了有效的Skyline計算。安裝RPREF包從查詢有問題可以通過(假設df是數據集的名稱)來完成:

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

這消除了只有那些元組,其中一些其他的元組是在兩個維度上更好。

如果需要另一個元組在一個維度上嚴格更好(並且在另一個維度上更好或相等),請改爲使用high(Col1) * high(Col2)

+0

哈!剛剛點擊了你的個人資料,看到了'rPref'的鏈接,然後直奔這裏,記下現在有一個更好的解決方案。會在我的回答中添加一個註釋,指向這裏的人,因爲否則你的答案几乎在雜草中消失了! – 2015-03-02 17:23:25

+0

這個包是否處理有兩個以上變量的有效邊界?假設我們想要包含n變量 – 2015-03-06 00:24:56

+0

是的,它的確如此。變量/維度的數量沒有主要限制,即高(x1)|高(x2)| ... |高(xn)'也是可能的,但計算成本(以及運行時間)將隨着維數的增加而增加。 – 2015-03-11 08:15:12