【问题标题】:Convert a text file of column and row names to a sparse matrix将列名和行名的文本文件转换为稀疏矩阵
【发布时间】:2014-02-28 06:46:04
【问题描述】:

我想从文本文件中获取列名和行名,并使用行和列信息构建一个稀疏矩阵(该算法可以在下面的描述中找到)。我有一个可行的解决方案,但对于包含超过 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

【问题讨论】:

  • 您是否尝试分析您的代码以查看它在哪里花费了这么多时间?
  • 我没有。我将分析代码并编辑我的问题。

标签: r performance algorithm indexing sparse-matrix


【解决方案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 

【讨论】:

  • 我使用您提供的示例数据为我工作。您可以使用格式略有不同的数据,这可能会在创建列表时导致错误。你能发布你实际使用的数据吗?它们是否以列名开头? (四个字符的长字符串)
  • 对不起,我现在已经删除了之前的评论。我现在在具有 >3,000,000 列名和行名的文件上运行您建议的算法。我会告诉你进展如何。
  • 谢谢 Zbynek,这更快了。
猜你喜欢
  • 2023-04-10
  • 2021-11-25
  • 2017-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 2020-11-26
  • 2020-12-07
相关资源
最近更新 更多