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