CSV到Vowpal输入格式-优化慢速R代码

CSV到Vowpal输入格式-优化慢速R代码,r,csv,vowpalwabbit,R,Csv,Vowpalwabbit,我试图建立一个快速的CSV到Vowpal输入格式转换器。我发现了一些与此相关的好代码,并以此为基础编写了我的示例。它在提供的小型泰坦尼克号数据集上非常有效,但我的真实数据集超过450万。具有200多个特征的观测。在功能强大的服务器上提供代码需要三天时间 这里有没有一种方法可以移除单回路?请记住,Vowpal有自己的稀疏性,因此代码每次都需要检查索引,以排除每行上的0或NAs。(与数据帧不同,vowpal不需要在每行中保留相同数量的功能)。我可以将每一行都写入文件,而不是全部保存在内存中。任何解决

我试图建立一个快速的CSV到Vowpal输入格式转换器。我发现了一些与此相关的好代码,并以此为基础编写了我的示例。它在提供的小型泰坦尼克号数据集上非常有效,但我的真实数据集超过450万。具有200多个特征的观测。在功能强大的服务器上提供代码需要三天时间

这里有没有一种方法可以移除单回路?请记住,Vowpal有自己的稀疏性,因此代码每次都需要检查索引,以排除每行上的0或NAs。(与数据帧不同,vowpal不需要在每行中保留相同数量的功能)。我可以将每一行都写入文件,而不是全部保存在内存中。任何解决方案都将不胜感激

# sample data set
titanicDF <- read.csv('http://math.ucdenver.edu/RTutorial/titanic.txt',sep='\t')
titanicDF  <- titanicDF  [c("PClass", "Age", "Sex", "Survived")]

# target variable
y <- titanicDF$Survived
lineHolders <- c()
for ( i in 1:nrow( titanicDF  )) {

    # find indexes of nonzero values - anything 
    # with zero for that row needs to be ignored!
    indexes = which( as.logical( titanicDF [i,] ))
    indexes <- names(titanicDF [indexes])

    # nonzero values
    values = titanicDF [i, indexes]

    valuePairs = paste( indexes, values, sep = ":", collapse = " " )

    # add label in the front and newline at the end
    output_line = paste0(y[i], " |f ", valuePairs, "\n", sep = "" )

    lineHolders <- c(lineHolders, output_line)
}
#样本数据集

titanicDF针对您最初提出的关于行上循环的问题,似乎在某种程度上,通过数据帧列而不是行来处理这个问题更快。我已将代码放入名为func_Row的函数中,如下所示

func_Row  <-  function(titanicDF) {
# target variable
y <- titanicDF$Survived
lineHolders <- c()
for ( i in 1:nrow( titanicDF  )) {
# find indexes of nonzero values - anything 
# with zero for that row needs to be ignored!
 indexes = which( as.logical( titanicDF [i,] ))
 indexes <- names(titanicDF [indexes])
# nonzero values
 values = titanicDF [i, indexes]
 valuePairs = paste( indexes, values, sep = ":", collapse = " " )
# add label in the front and newline at the end
 output_line = paste0(y[i], " |f ", valuePairs, "\n", sep = "" )
 lineHolders <- c(lineHolders, output_line)
} 
return(lineHolders)
}
请注意,这组数据的结果以毫秒为单位。因此,按列处理的速度大约是按行处理的50倍。解决内存问题非常简单,通过读取行块中的数据来保留按列处理的好处。我根据泰坦尼克号数据创建了5300000行文件,如下所示

titanicDF_big <- titanicDF
for( i in 1:12 )  titanicDF_big <- rbind(titanicDF_big, titanicDF_big)
write.table(titanicDF_big, "titanic_big.txt", row.names=FALSE )

块大小越大,时间就越好,但需要更多内存。然而,这些结果表明,通过按列处理数据,即使块大小约等于文件大小的10%,整个530万行扩展的Titanic数据文件也可以在大约一分钟或更短的时间内读取。同样,结果将取决于数据和系统属性的列数。

至少要预先分配
行持有者。在R中增长对象是您可能做的最不明智的事情。其他想法:以矢量化的方式预先添加标签,以及将粘贴在一起的所有其他部分。然后在列表列表中重新组织所有内容,并使用
lappy
。如果速度很重要的话,R不是我重塑文本文件的第一选择。Python或Perl可能会更快地使用它。但是你分析过这段代码吗?移除一个循环并不能保证使任何事情都更快。下一个最好的方法是将文件拆分并并行转换块。然后你可以根据你可以访问的处理器的数量来减少你的时间。谢谢各位-原始的libsvm脚本将每一行写入文件,避免了内存问题。如果我能找到解决并发磁盘写入的好方法,我可能不得不尝试分布式任务。谢谢你的意见!可能更容易将所需的列写入新的.csv并使用PHRUG,这是大众自己为转换编写的工具-我不会复制/粘贴,但我在这里创建了一个与操作列相关的。。。到目前为止,我看到的示例仍然非常慢…感谢您使用timeout-def。通过接近本专栏来改进!
microbenchmark( func_Row(titanicDF), func_Col(titanicDF), times=10)
Unit: milliseconds
            expr        min         lq     median         uq       max neval
func_Row(titanicDF) 370.396605 375.210624 377.044896 385.097586 443.14042    10
func_Col(titanicDF)   6.626192   6.661266   6.675667   6.798711  10.31897    10
titanicDF_big <- titanicDF
for( i in 1:12 )  titanicDF_big <- rbind(titanicDF_big, titanicDF_big)
write.table(titanicDF_big, "titanic_big.txt", row.names=FALSE )
read_blocks <- function(file_name, row_max = 6000000L, row_block = 5000L ) {
#   Version of code using func_Col to process data by columns
blockDF = NULL
for( row_num in seq(1, row_max, row_block)) { 
  if( is.null(blockDF) )  {
    blockDF <- read.table(file_name, header=TRUE, nrows=row_block)
    lineHolders <- func_Col(blockDF)
  }  
  else  {
    blockDF <- read.table(file_name, header=FALSE, col.names=names(blockDF),
                            nrows=row_block, skip = row_num - 1)
    lineHolders <- c(lineHolders, func_Col(blockDF))
  }
}
return(lineHolders)
}
Unit: seconds
                                                                 expr      min       lq       median       uq      max neval
 read_blocks("titanic_big.txt", row_max = 6000000L, row_block = 2000000L) 39.43244 39.43244 39.43244 39.43244 39.43244     1
 read_blocks("titanic_big.txt", row_max = 6000000L, row_block = 1000000L) 46.66375 46.66375 46.66375 46.66375 46.66375     1
 read_blocks("titanic_big.txt", row_max = 6000000L, row_block = 500000L) 62.51387 62.51387 62.51387 62.51387 62.51387     1