※ 引述《clansoda (小笨)》之铭言:
: 我自己来回我自己的问题 我采用的解法是andrew大的解法
: C版的解法看起来应该是最快的 但是小弟无法理解在干嘛
: 所以选择了一个看起来比我的快很多又能理解的方法
: kk <- Sys.time()
: klist <- lapply(1 : NROW(target), function(k){
: target[k,] %>% as.numeric %>% .[!is.na(.)]
: })
: test <- lapply(klist, function(k) {
: m <- logical(20)
: m[k] <- TRUE
: return(m)
: }) %>% do.call(rbind, .)
: Sys.time() - kk
: Time difference of 53.88025 secs
: 我稍微修正过andrew大在提取每个row里的值成为list的这一段码
: 这样可以将速度从180几秒提到50秒左右
: 以我目前这个50万row的资料等级来说这个速度我个人可以接受了
: 等到C大提点他的程式码的逻辑以后可能会再修改我的写法
: 目前先到这样 感谢各位先进的提供的作法 受益良多
结果应该是一样的,程式:
library(data.table)
target <- fread('
a b c
2 5 NA
1 NA NA
1 2 3
3 NA NA
2 4 NA
1 4 5
')
mat <- as.matrix(target)
library(magrittr)
system.time({
klist <- lapply(1 : NROW(target), function(k){
target[k,] %>% as.numeric %>% .[!is.na(.)]
})
test <- lapply(klist, function(k) {
m <- logical(5)
m[k] <- TRUE
return(m)
}) %>% do.call(rbind, .)
})
system.time({
idx <- nrow(mat) * (mat - 1L)
idx <- idx[which(!is.na(idx))] + which(!is.na(mat), arr.ind = TRUE)[, 1]
out <- matrix(FALSE, nrow(mat), 5L)
out[idx] <- TRUE
dim(out) <- c(nrow(mat), 5L)
})
all.equal(test, out) # TRUE
我程式有点偷懒,是因为假设level数跟input的coloumn数会一样
我这里解释一下我的程式逻辑:
我们先看一下输出的结果
[,1] [,2] [,3] [,4] [,5]
[1,] FALSE TRUE FALSE FALSE TRUE
[2,] TRUE FALSE FALSE FALSE FALSE
[3,] TRUE TRUE TRUE FALSE FALSE
[4,] FALSE FALSE TRUE FALSE FALSE
[5,] FALSE TRUE FALSE TRUE FALSE
[6,] TRUE FALSE FALSE TRUE TRUE
第一列是2, 5要为TRUE,对应到input的第一列 2, 5, NA
第二列是1是TRUE,对应到input的第一列 1, NA, NA
所以我只要有(1, 2), (1, 5), (2, 1), ... 的位置向量
就可以把TRUE位置都描述出来
而且(1, 2), (1, 5), ...这些位置也可以用一个index表示
(这里计算是根据coloumn-major的矩阵,row-major则会有一点不同)
矩阵中 (1, 2)位置其实可以用 1 + nrow(matrix) * (2 - 1) = 7 (这列有6个row)
(1, 5)位置可以用 1 + nrow(matrix) * (5 - 1) = 25
(2, 1)位置可以用 2 + nrow(matrix) * (1 - 1) = 2 ...
来表示
所以我们可以得到一个通式:
(i, j) => i + nrow(matrix) * (j - 1)
换到我的程式上来看
这行 idx <- nrow(mat) * (mat - 1L) 是把后面那个部分算出来
可是因为mat里面充满了NA,所以要满NA先移除掉就有了下一行的前半段:
idx[which(!is.na(idx))]
那i要怎么办,就利用which + !is.na去把对应的列位置取出
于是我们就得到了TRUE位置的index:
idx <- idx[which(!is.na(idx))] + which(!is.na(mat), arr.ind = TRUE)[, 1]
那最后我只要把output的矩阵弄出来:
out <- matrix(FALSE, nrow(mat), 5L)
# 这里的5是指target中最大的数字,可以用max(mat[!is.na(mat)])取得
然后再把TRUE位置补上,改一下dim:
out[idx] <- TRUE
dim(out) <- c(nrow(mat), 5L) # 这个5同前面的5意思
如此一来就可以得到正确答案了
这个方法比较tricky一点,但是向量化的精神就在这里
向量化的程式需要一点的数学 跟 逻辑推演,不是那么直觉就写得出来
但是它的performance会真的很好~~~~