2016-12-06 80 views
0

我需要将大矩阵转换为与libsvm一起使用的特定格式。该格式包含开始每一行与一个标签(1或-1),接着0:ROW_NUMBER和行的值作为1:value_at_row_number_1st_column加快矩阵格式化

下面给出的简单的方法是太慢,

require(microbenchmark) 
nR = 100; nC = 500 
kMat = matrix(runif(nR*nC), nrow=nR) 
yLab = sample(c(1, -1), nR, replace = T) 

# Simple method 
met1 = function() { 
    lines = c() 
    for(ix in 1:nrow(kMat)) 
    lines = c(lines, 
      paste(yLab[ix], 
       paste0("0:", ix), 
       paste0(1:ncol(kMat), ":", kMat[ix, ], collapse=" "))) 
    lines 
} 

我也取得了较快〜50%的版本(虽然这样丑陋的),

# Sprintf 
met2 = function() { 
    fmt = c("%i", "0:%i", paste0(1:ncol(kMat), ":%f")) 
    kMat = cbind(yLab, 1:nrow(kMat), kMat) 
    # Unfortunately sprintf cannot handle more than 100 arguments 
    splts = lapply(seq(1, length(fmt), 99L), 
       function(ix) { 
        r = ix:min(ncol(kMat), ix+98L) 
        list(range = r, fmt = list(paste(fmt[r], collapse =  " "))) 
      }) 
    lines = sapply(1:nrow(kMat), 
       function(ix) { 
        Reduce(function(a, b) sprintf("%s %s", a, b), 
          sapply(splts, 
           function(s){ 
            do.call(sprintf, c(s$fmt, kMat[ix, s$range])) 
           }), 
          "") 
       }) 
    lines 
} 
print(microbenchmark(met1(), met2())) 

Unit: milliseconds 
    expr  min  lq  mean median  uq  max neval 
met1() 85.83051 88.00289 92.01948 88.61834 90.31918 175.3362 100 
met2() 44.81729 45.61020 56.12835 54.75313 56.65249 108.7218 100 

是否有更快(或更整洁)的方式来处理这种格式?

+0

90毫秒是太慢? – Roland

+0

这只是一个测试样本,我将在更大的集合上工作,也会多次重复该操作 – jMathew

+0

我并不乐观,您可以使用R做得更好。您可能需要切换到其他语言。 – Roland

回答

0

这既短又快。看起来sprintfdoublecharacter完成的转换似乎比隐含的as.character快,并且stringi::stri_joinpastepaste0提供了一点加速。我也尝试了转置被消除的变体,但下面的代码更快。

library(stringi) 

met3 <- function() { 
    s <- stri_join("0:", seq_len(nC), " ", sprintf("%f", t(kMat))) 
    m <- matrix(s, nC) 
    stri_join(yLab, apply(m, 2, stri_join, collapse = " "), sep = " ") 
} 

,并提供:

> microbenchmark(met3(), met2(), times = 10) 
Unit: milliseconds 
    expr  min  lq  mean median  uq  max neval 
met3() 236.6127 255.1396 264.7797 256.6331 292.1037 296.6377 10 
met2() 307.6371 322.1467 354.7281 332.0041 388.2474 464.2259 10 
+0

请注意,这已被修改了几次,现在比问题中的代码更快。 –

+0

嗯,你的方法没有提高我的测试速度..最好它等于'met2' – jMathew

+0

我在Windows 10笔记本电脑上使用“R开发中(不稳定)(2016-12-04 r71726)” 。虽然它在我尝试它时没有帮助,因为你得到不同的时间,你可以尝试消除转置。 –