我遇到了问题,但是我在网上找不到令人满意的答案。我想使用start:end向量来定值一个data.frame(对我来说也是一个data.table)。一个例子将阐明我的要求。
假设我有一个data.frame,如下所示:
df <- data.frame(col_1 = rep(0, 3), col_2 = rep(0, 3), col_3 = rep(0, 3), col_4 = rep(0,3))
df
col_1 col_2 col_3 col_4
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
假设我有两个向量:
indexesStart <- c(1, 2, 1)
indexesEnd <- c(2, 4, 3)
我想将矢量按行表示的范围内的所有值均值化为1。输出应为以下内容:
col_1 col_2 col_3 col_4
1 1 1 0 0
2 0 1 1 1
3 1 1 1 0
我尝试过这样的事情:
df[ , indexesStart:indexesEnd] <- 1
但是它不起作用,它只需要indexesStart[1]:indexesEnd[1]
并对所有行重复一次。
我必须避免循环循环,因为我的实际数据帧有数百万行,而且速度太慢。感谢您的帮助(data.table
解决方案会更好)
谢谢
答案 0 :(得分:2)
这可以做到:
df <- data.frame(col_1=rep(0,3),col_2=rep(0,3),col_3=rep(0,3),col_4=rep(0,3))
indexesStart <- c(1, 2, 1)
indexesEnd <- c(2, 4, 3)
for (i in 1:nrow(df)) df[i, indexesStart[i]:indexesEnd[i]] <- 1
df
这是另一种使用双列矩阵作为索引的技术:
I <- do.call(rbind, lapply(1:length(indexesStart), function(i) cbind(i, indexesStart[i]:indexesEnd[i])))
df[I] <- 1
在第二个变体中,我隐藏了循环(隐藏的循环位于另一个位置)。
答案 1 :(得分:0)
尝试此操作,它避免了任何循环或重复应用,并且被矢量化了。这利用了一个事实,即data.frame实际上是一个列表。
impute <- function(lst, start, end){ lst[start:end] <- 1; lst }
fill <- function(df, start, end){
cols <- names(df)
lst <- as.list(as.data.frame(t(df)))
res <- as.data.frame(t(Vectorize(impute)(lst, start, end)))
names(res) <- names(df)
row.names(res) <- row.names(df)
res
}
res <- fill(df, indexesStart, indexesEnd)
花大约5秒钟的时间在MacBook Pro上执行100万行。