我正在收集关于我的猫粪便多少的数据:
m <- cbind(fluffy=c(1.1,1.2,1.3,1.4),misterCuddles=c(0.9,NA,1.1,1.0))
row.names(m) <- c("2013-01-01", "2013-01-02", "2013-01-03","2013-01-04")
Run Code Online (Sandbox Code Playgroud)
这给了我这个:
fluffy misterCuddles
2013-01-01 1.1 0.9
2013-01-02 1.2 NA
2013-01-03 1.3 1.1
2013-01-04 1.4 1.0
Run Code Online (Sandbox Code Playgroud)
在每个日期,我想知道每只猫连续多少天已经走了2号.所以结果矩阵应如下所示:
fluffy misterCuddles
2013-01-01 1 1
2013-01-02 2 0
2013-01-03 3 1
2013-01-04 4 2
Run Code Online (Sandbox Code Playgroud)
有没有办法有效地做到这一点?该cumsum函数做了类似的事情,但这是一个原始的,所以我无法修改它以满足我的脏,脏需求.
我可以运行for循环并存储计数如下:
m.output <- matrix(nrow=nrow(m),ncol=ncol(m))
for (column in 1:ncol(m)) {
sum <- 0
for (row in 1:nrow(m)) {
if (is.na(m[row,column])) sum <- 0
else sum <- sum + 1
m.output[row,column] <- sum
}
}
Run Code Online (Sandbox Code Playgroud)
这是最有效的方法吗?我有很多猫,我记录了多年的便便数据.我可以通过某种方式将其平行化吗?
Tho*_*mas 11
这里的所有答案实际上都太复杂了(包括我自己,以前复制过,下面复制).该Reduce答案的家庭只是掩盖了一个函数调用一个for循环.我喜欢Roland和Ananda的,但我认为这两者都有点太多了.
因此,这是一个简单的矢量化解决方案:
reset <- function(x) {
s <- seq_along(x)
s[!is.na(x)] <- 0
seq_along(x) - cummax(s)
}
> apply(m, 2, reset)
fluffy misterCuddles
[1,] 1 1
[2,] 2 0
[3,] 3 1
[4,] 4 2
Run Code Online (Sandbox Code Playgroud)
它也适用于Roland的例子:
m2 <- cbind(fluffy=c(NA,1.1,1.2,1.3,1.4,1.0,2),
misterCuddles=c(NA,1.3,2,NA,NA,1.1,NA))
> apply(m2, 2, reset)
fluffy misterCuddles
[1,] 0 0
[2,] 1 1
[3,] 2 2
[4,] 3 0
[5,] 4 0
[6,] 5 1
[7,] 6 0
Run Code Online (Sandbox Code Playgroud)
从早些时候开始:这不是矢量化,但也有效:
pooprun <- function(x){
z <- numeric(length=length(x))
count <- 0
for(i in 1:length(x)){
if(is.na(x[i]))
count <- 0
else
count <- + count + 1
z[i] <- count
}
return(z)
}
apply(m, 2, pooprun)
> apply(m, 2, pooprun)
fluffy misterCuddles
[1,] 1 1
[2,] 2 0
[3,] 3 1
[4,] 4 2
Run Code Online (Sandbox Code Playgroud)
基准
在这里,我简单地将每个人的答案包装在一个函数调用中(基于他们的名字).
> library(microbenchmark)
> microbenchmark(alexis(), hadley(), thomas(), matthew(), thomasloop(), usobi(), ananda(), times=1000)
Unit: microseconds
expr min lq median uq max neval
alexis() 1.540 4.6200 5.3890 6.1590 372.185 1000
hadley() 87.755 92.758 94.298 96.6075 1767.012 1000
thomas() 92.373 99.6860 102.7655 106.6140 315.223 1000
matthew() 128.168 136.2505 139.7150 145.4880 5196.344 1000
thomasloop() 133.556 141.6390 145.1030 150.4920 84131.427 1000
usobi() 148.182 159.9210 164.7320 174.1620 5010.445 1000
ananda() 720.507 742.4460 763.6140 801.3335 5858.733 1000
Run Code Online (Sandbox Code Playgroud)
以下是Roland示例数据的结果:
> microbenchmark(alexis(), hadley(), thomas(), matthew(), thomasloop(), usobi(), ananda(), times=1000)
Unit: microseconds
expr min lq median uq max neval
alexis() 2.310 5.3890 6.1590 6.9290 75.438 1000
hadley() 75.053 78.902 80.058 83.136 1747.767 1000
thomas() 90.834 97.3770 100.2640 104.3050 358.329 1000
matthew() 139.715 149.7210 154.3405 161.2680 5084.728 1000
thomasloop() 144.718 155.4950 159.7280 167.4260 5182.103 1000
usobi() 177.048 188.5945 194.3680 210.9180 5360.306 1000
ananda() 705.881 729.9370 753.4150 778.8175 8226.936 1000
Run Code Online (Sandbox Code Playgroud)
注:亚历克西斯的和哈德利的解决方案花了相当长的一段实际上定义为我的机器上的功能,而其他工作外的开箱,但亚历克西斯的,否则是明显的赢家.
这应该工作.请注意,您的每只猫都是独立的个体,因此您可以将数据框转换为列表并使用mclapply并行方法.
count <- function(y,x){
if(is.na(x)) return(0)
return (y + 1)
}
oneCat = m[,1]
Reduce(count,oneCat,init=0,accumulate=TRUE)[-1]
Run Code Online (Sandbox Code Playgroud)
编辑:这是完整的答案
count <- function(x,y){
if(is.na(y)) return(0)
return (x + 1)
}
mclapply(as.data.frame(m),Reduce,f=count,init=0,accumulate=TRUE)
Run Code Online (Sandbox Code Playgroud)
编辑2:主要的不好的问题是我在开始时得到额外的0,所以......
result = mclapply(as.data.frame(m),Reduce,f=count,init=0,accumulate=TRUE)
finalResult = do.call('cbind',result)[-1,]
rownames(finalResult) = rownames(m)
Run Code Online (Sandbox Code Playgroud)
做的工作.