2011-05-23 62 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) 
} 
)