2013-10-17 123 views
0

當通過某些條件對data.frames進行子集化時,如果數據幀包含NA,則可能會出現由於條件而得到NA值。然後,它會令問題在子集化data.frame:索引數據幀中的NA值

# data generation 
set.seed(123) 
df <- data.frame(a = 1:100, b = sample(c("moon", "venus"), 100, replace = TRUE), c = sample(c('a', 'b', NA), 100, replace = TRUE)) 

# indexing 
with(df, df[a < 30 & b == "moon" & c == "a",]) 

你得到:

 a b c 
NA NA <NA> <NA> 
10 10 moon a 
12 12 moon a 
NA.1 NA <NA> <NA> 
NA.2 NA <NA> <NA> 
29 29 moon a 

這是因爲條件導致載體含港定居,然後將這些NAS會產生上述結果的索引數據幀。

其中一個解決方案將是這些修補程序之一:

with(df, df[a < 30 & b == "moon" & (c == "a" & !is.na(c)),]) # exclude NAs 
with(df, df[a < 30 & b == "moon" & (c == "a" | is.na(c)),]) # include NAs 

,但這些都是非常笨拙的 - 假設你有很長的情況一樣 df[A == x1 & B == x2 & C == x3 & D == x4,],你必須包裝這樣的每一個元素 - df[(A == x1 | is.na(A)) & (B == x2 | is.na(B)) ...,]

是否有任何優雅的解決方案,這不需要你在控制檯上寫這些噸的代碼,如果你只是試圖檢查數據框?

+2

這個問題可以做些什麼來排除值,而不增加咆哮。這種行爲在'?Extract',「愚蠢」或者沒有被廣泛記錄。 –

+0

@ SimonO101:然後在那裏發佈答案,或者更新Shane的答案。我只是試圖讓有用的內容分散在多個問題上。 –

回答

4

好吧,如果你想省略NA行,一個快速和hackish的解決辦法是把它包在which

> with(df, df[a < 30 & b == "moon" & c == "a",]) 
     a b c 
NA NA <NA> <NA> 
10 10 moon a 
12 12 moon a 
NA.1 NA <NA> <NA> 
NA.2 NA <NA> <NA> 
29 29 moon a 
> with(df, df[which(a < 30 & b == "moon" & c == "a"),]) 
    a b c 
10 10 moon a 
12 12 moon a 
29 29 moon a 

的編輯:在這樣的情況下,另一種選擇,這可能經讓人不悅一些,但我個人覺得非常有用的,是在括號內定義一個局部變量:

> with(df, df[{i<-a < 30 & b == "moon" & c == "a"; i | is.na(i)},]) 
    a b c 
6 6 moon <NA> 
10 10 moon a 
12 12 moon a 
15 15 moon <NA> 
18 18 moon <NA> 
29 29 moon a 
> with(df, df[{i<-a < 30 & b == "moon" & c == "a"; i & !is.na(i)},]) 
    a b c 
10 10 moon a 
12 12 moon a 
29 29 moon a 

這是更簡潔比任何寫一個特殊的函數或定義在單獨的行索引,並且適用於許多沒有R功能的情況下,你正是想要的。

+0

+1我認爲這基本上是我的建議,但它更好,更簡潔地使用'which'。 –

+0

不錯的解決方案!它幾乎完美!從我的觀點來看,絕對完美的解決方案就像是一些全局參數設置,它可以改變'['操作符在NAs上的工作方式... – TMS

1

您可以使用data.table包。這將簡化代碼,因爲您不必將所有內容都包含在with(df, ...)中,並且它將NAs視爲FALSE。

require(data.table) 
dt <- data.table(df) 
dt[a < 30 & b == "moon" & c == "a",] # exclude NAs 
dt[a < 30 & b == "moon" & (c == "a"|is.na(c)),] # include NAs 
+0

謝謝,有趣! – TMS

1
clean <- function(x, include = FALSE){ 
    x[is.na(x)] <- include 
    x 
} 

# Original output 
with(df, df[a < 30 & b == "moon" & c == "a",]) 
# Clean it up and remove NAs 
with(df, df[clean(a < 30 & b == "moon" & c == "a"),]) 
# Clean it up but include NAs 
with(df, df[clean(a < 30 & b == "moon" & c == "a", include = TRUE),]) 

這給

> with(df, df[a < 30 & b == "moon" & c == "a",]) 
     a b c 
NA NA <NA> <NA> 
10 10 moon a 
12 12 moon a 
NA.1 NA <NA> <NA> 
NA.2 NA <NA> <NA> 
29 29 moon a 
> 
> with(df, df[clean(a < 30 & b == "moon" & c == "a"),]) 
    a b c 
10 10 moon a 
12 12 moon a 
29 29 moon a 
> with(df, df[clean(a < 30 & b == "moon" & c == "a", include = TRUE),]) 
    a b c 
6 6 moon <NA> 
10 10 moon a 
12 12 moon a 
15 15 moon <NA> 
18 18 moon <NA> 
29 29 moon a 

使用which也可以工作,但它只會讓你在默認情況下