只遍历(假设很少)N 个实例怎么样:
addZeros <- function(x, N = 3) {
xx <- x
z <- x - 1
for (i in 1:N) {
xx <- xx + c(rep(0, i), z[-c((NROW(x) - i + 1):NROW(x))])
}
xx[xx<0] <- 0
xx
}
只需将所有零实例变为 -1 即可减去 N 个后续值。
> x <- c(1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1)
> x
[1] 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1
[39] 1 1 1 1 1 1 0 0 1 0 1
> addZeros(x)
[1] 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1
[39] 1 1 1 1 1 1 0 0 0 0 0
编辑:
在阅读了您对 R-help 邮件列表中数据的描述后,这显然不是小 N 的情况。因此,您可能需要为此考虑使用 C 函数。
在文件“addZeros.c”中:
void addZeros(int *x, int *N, int *n)
{
int i, j;
for (i = *n - 1; i > 0; i--)
{
if ((x[i - 1] == 0) && (x[i] == 1))
{
j = 0;
while ((j < *N) && (i + j < *n) && (x[i + j] == 1))
{
x[i + j] = 0;
j++;
}
}
}
}
在命令提示符下(Windows 中的 MS DOS,按 Win+r 并输入 cmd),输入“R CMD SHLIB addZeros.c”。如果无法到达 R 的路径(即“未知的 kommand R”),您需要说明完整地址(在我的系统上:
"c:\Program Files\R\R-2.10.1\bin\R.exe" CMD SHLIB addZeros.c
在 Windows 上,这应该会生成一个 DLL(在 Linux 中是 .so),但如果您还没有 R-toolbox,您应该下载并安装它(它是工具的集合,例如 Perl 和 Mingw)。从http://www.murdoch-sutherland.com/Rtools/下载最新版本
用于此的 R 包装函数将是:
addZeros2 <- function(x, N) {
if (!is.loaded("addZeros"))
dyn.load(file.path(paste("addZeros", .Platform$dynlib.ext, sep = "")))
.C("addZeros",
x = as.integer(x),
as.integer(N),
as.integer(NROW(x)))$x
}
setwd("C:/Users/eyjo/Documents/Forrit/R/addZeros")
请注意,在第一次调用 addZeros R 函数之前,R 中的工作目录应该与 DLL(在我的系统上)相同(或者,dyn.load
只包含 dll 文件的完整路径)。最好将它们保存在项目下的子目录中(即“c”),然后在文件路径中的“addZeros”前面添加“c/”。
为了显示:
> x <- rbinom(1000000, 1, 0.9)
>
> system.time(addZeros(x, 10))
user system elapsed
0.45 0.14 0.59
> system.time(addZeros(x, 400))
user system elapsed
15.87 3.70 19.64
>
> system.time(addZeros2(x, 10))
user system elapsed
0.01 0.02 0.03
> system.time(addZeros2(x, 400))
user system elapsed
0.03 0.00 0.03
>
其中“addZeros”是我最初的建议,只有内部 R,而 addZeros2 正在使用 C 函数。