2011-05-23 40 views
6

希望這不是一個太愚蠢的問題,但仍然是一個R初學者我有一個嚴重的問題與tapply。比方說如何使用tapply並保存值的順序

factors <- as.factor(c("a", "b", "c", "a", "b", "c", "a", "b", "c")) 
values <- c(1, 2, 3, 4, 5, NA, 7, NA, NA) 
tapply(
    values, 
    factors, 
    function(x){ 
    if(sum(is.na(x)) == 1){ 
     x[ is.na(x) ] <- 0 
    } 
    return(x) 
    } 
) 

結果是

$a 
[1] 1 4 7 

$b 
[1] 2 5 0 

$c 
[1] 3 NA NA 

不過,我需要的是得到一個向量回其保留值的原始順序,即:

c(1,2,3,4,5,NA,7,0,NA) 

很多感謝提前。

+0

這是我在stackoverflow上的第一個問題,我對快速h elp我得到了。非常感謝所有人。 – Beasterfield 2011-05-24 00:50:55

+4

這是因爲你的問題很清楚,包含所有相關的信息和數據。 – Marek 2011-05-24 08:13:19

回答

7

在這種情況下,你應該使用ave功能:

> ave(values, factors, FUN=function(x) { 
+  if(sum(is.na(x)) == 1){ 
+  x[ is.na(x) ] <- 0 
+  } 
+  return(x) 
+ } 
+) 
[1] 1 2 3 4 5 NA 7 0 NA 
+0

這幫了很多,謝謝! – Beasterfield 2011-05-23 23:16:41

+1

是的。 ave功能非常酷。你只需要記住明確地使用... FUN = – 2011-05-23 23:41:36

+0

確實,花了我幾分鐘才弄明白。但是你的回答仍然讓我感到高興。 – Beasterfield 2011-05-24 00:50:19

1

簡單for循環做到這一點很簡單:

fun <- function(x){ 
    if(sum(is.na(x)) == 1){x[is.na(x)] <- 0} 
     return(x) 
} 

for (i in unique(factors)){ 
    values[i == factors] <- fun(values[i == factors]) 
} 
+0

我也想過這個。但是,並不是所有這些應用函數的時間比用循環手動迭代數據快嗎?特別是因爲計算需求是我的數據的問題。 – Beasterfield 2011-05-23 23:19:21

+0

並不總是,tapply和apply只是語法糖。在控制檯中查看tapply()的源代碼'tapply'。我想這一點的確是迭代次數通常會比每次迭代的數據長度要小。 – mdsumner 2011-05-23 23:23:40

+0

我同意mdsumner,雖然在這種情況下,我相信使用'ave()'的迪文答案比明確的for循環要快得多。 – joran 2011-05-23 23:33:31

0

一種選擇是使用的拆分)的替換方法(:

## create a copy to store the result after replacement 
res <- values 

## use split's replacement method to split, apply, and recombine 
split(res, factors) <- lapply(split(res, factors), 
function(x){ 
if(sum(is.na(x)) == 1){ 
    x[ is.na(x) ] <- 0 
} 
    return(x) 
} 
) 
相關問題