将列名和行名的文本文件转换为稀疏矩阵

时间:2014-02-04 10:40:32

标签: r performance algorithm indexing sparse-matrix

我想从文本文件中获取列名和行名,并使用行和列信息构建稀疏矩阵(该算法可在下面的描述中找到)。我有一个有效的解决方案,但对于包含超过3,000,000个条目的文本文件来说,它很慢。

有没有人对比我在下面描述的算法更快的算法有任何建议?

首先,我从一个文本文件开始,该文件提供以空格分隔的列名和行名。例如:

aaaa 11111 22222 33333 bbbb 11111 22222 cccc 11111

其中{aaaa,bbbb,cccc}是4个字符的列名,{11111,22222,33333}是5个字符的行名。

其次,我使用扫描功能将此文本文件加载到R

char_vec <- scan(file = "textFile.txt", what = "character")

将textFile信息转换为字符向量。

第三,我找到了所有可能的列名和行名:

c_names <- unique(char_vec[nchar(char_vec) == 4])
r_names <- unique(char_vec[nchar(char_vec) == 5])

第四,我从数据中创建一个稀疏矩阵:

library(Matrix)
createMatrix <- function(char_vec=char_vec, c_names=c_names, r_names=r_names)
{
  mySparseMatrix <- Matrix(0, nrow = length(r_names), ncol = length(c_names), 
  sparse = TRUE)
  for (i1 in 1:length(char_vec))
  {
    if (char_vec[i1] %in% c_names)
    {
      c_index <- match(char_vec[i1], c_names)
    }
    if (char_vec[i1] %in% r_names)
    {
      r_index <- match(char_vec[i1], r_names)
      mySparseMatrix[r_index, c_index] <- 1
    }
  }
  colnames(mySparseMatrix) <- c_names
  rownames(mySparseMatrix) <- r_names
  return(mySparseMatrix)
}

这给出了这个输出:

      aaaa bbbb cccc
11111    1    1    1
22222    1    1    .
33333    1    .    .

为了说明这个算法的工作速度,我填写了字符向量(尽管是以不切实际的方式,但我认为它的目的是作为一个例子):

char_vec <- rep(c("aaaa", "11111", "22222", "33333", "bbbb", "11111", "22222", "cccc", "11111"), 1000)

然后跑了:

system.time(createMatrix(char_vec, c_names, r_names))

输出:

   user  system elapsed 
   9.89    0.00    9.94

我使用以下方式分析了该功能:

Rprof("createMatrixOut.out")
z <- createMatrix(char_vec, c_names, r_names)
Rprof(NULL)

并使用以下方式显示输出的子集:

summaryRprof("createMatrixOut.out")$by.total[1:10,]

输出:

                  total.time total.pct self.time self.pct
"createMatrix"          8.08    100.00      0.08     0.99
"[<-"                   7.96     98.51      0.08     0.99
"replCmat4"             7.40     91.58      0.04     0.50
"as"                    5.64     69.80      0.04     0.50
"asMethod"              5.06     62.62      0.16     1.98
"standardGeneric"       4.68     57.92      0.24     2.97
"new"                   4.52     55.94      0.02     0.25
"initialize"            4.40     54.46      0.04     0.50
"callNextMethod"        4.24     52.48      0.08     0.99
".Call"                 4.12     50.99      0.60     7.43

1 个答案:

答案 0 :(得分:1)

我更改了数据的结构:我创建了列表:

,而不是将它们存储在字符向量中
> lst
$aaaa
[1] "11111" "22222" "33333"

$bbbb
[1] "11111" "22222"

$cccc
[1] "11111"

迭代这个列表要快得多

createMatrix2 <- function(char_vec=char_vec, c_names=c_names, r_names=r_names)
{
  # create list
  lst <- list()
  for (i1 in 1:length(char_vec))
  {
    if (nchar(char_vec[i1])==4)
    {
      cn <- char_vec[i1]
    } else {
      if (!(char_vec[i1] %in% lst[[cn]])){lst[[cn]] <- c(lst[[cn]],char_vec[i1])}
    }

  }

  # create empty matrix
  mySparseMatrix <- Matrix(0, nrow = length(r_names), ncol = length(c_names), 
                           sparse = TRUE)

  # fill the matrix
  for (cn in names(lst)){
    c_index <- match(cn, c_names)
    for(rn in lst[[cn]]){
      r_index <- match(rn, r_names)
      mySparseMatrix[r_index, c_index] <- 1
    }
  }

  # names and return
  colnames(mySparseMatrix) <- c_names
  rownames(mySparseMatrix) <- r_names
  return(mySparseMatrix)
}


> system.time(createMatrix(char_vec, c_names, r_names))
   user  system elapsed 
   9.60    0.00   10.36 

> system.time(createMatrix2(char_vec, c_names, r_names))
   user  system elapsed 
   0.06    0.00    0.06