【问题标题】:Export named variable in foreach loop在 foreach 循环中导出命名变量
【发布时间】:2017-11-14 15:07:54
【问题描述】:

我有一个大的 data.table(+12M 行),我需要以这种方式进行转换:
将具有相同第一列值(我们称之为 BookId)的每一行折叠为 1 行,并将其他列合并为一个大的“数据”字段。 此表包含 270 万个唯一 BookId

即:

BookId Col1 Col2 ... ColN B001 作者鲍勃…… B002 作者马克…… B002 编辑器 Bob Inc ... ... B001 编辑器 MyBooks ... ...

加速结果:

BookId 数据
B001 鲍勃,我的书,...
B002 马克,鲍勃公司,...

目前,我已经能够使用子集重现此结构,但这确实很慢,构建一行需要 300 毫秒,这意味着完成该过程最多需要 9 天。

所以我决定使用一个并行的 foreach 循环来加快这个过程。
我的第一个方法是遍历 bookId 列表,但它只会将全局总时间划分为不令人满意的核心数量(8 个核心意味着 +1 天)。此外,这意味着每个进程都会自动导出大量数据,因为它们都需要整个 data.table 对象。

我找到了另一种改进流程的方法,方法是根据 bookId 列表将主 data.table 拆分为独立的子集,然后让每个集群在这些子集上工作(更少的行意味着更快的子集生成)。 不幸的是,我无法将我的子集导出到集群,因为它们具有“动态”名称。 我尝试了“.export”参数,但我猜它在评估时不知道当前的“i”值。 我怎样才能做到这一点?有可能吗?

我是 R 新手,有人告诉我,总是有很多方法可以实现相同的目标,我是否选择了实现这一目标的最佳方法?

这是我的代码:

# Create cluster based on available cores
cores = detectCores()
cl <- makeCluster(cores)
registerDoParallel(cl)

# Load datas and generate BookId lists
books <- fread("books.tab")
bookId.unique.list <- unique(books$BookId)
bookId.list <- books$BookId

# Split datatable into "equals" subsets
subset.length = ceiling(length(book.unique.list)/cores)
for (i in 1:(cores)) {
    start = (i-1)*subset.length
    end = (i)*subset.length
    list = book.unique.list[start:end]
    assign(paste("books",i,sep=""), books[books$BookId %in% list])
    assign(paste("book.list",i,sep=""), list )
}

# Prepare resulting DT
res = data.table(BookId = character(0), data = character(0))

# Parallel loop
res  <- foreach(i = 1:cores, .combine = rbind, .export = paste0("book", i),  .packages = c("data.table")) %dopar% {

    #Try to get the named subset corresponding to the current iteration (i)
    # IE : Books1, Books2...
    BookSubset = get(paste0("book", i))
    Book.list.subset = unique(BookSubset$BookId)

    temp = data.table(BookId = character(0), data = character(0))

    for (i in 1:length(Book.list.subset)) {
        bookId = Book.list.subset[i]

        subset <- BookSubset[which(Book.list.subset ==bookId)]
        output = capture.output(write.table(subset, stdout()quote=FALSE, row.names=FALSE,col.names=FALSE)

      temp <- rbind(hist, data.table(zkf_BOOK = c(bookId), data = c(output)))
    }
    temp
}

这是dput[head(books))的结果:

structure(list(BookId = c("BOOKXXXX774051532082", "BOOKXXXX776514515608", 
    "BOOKXXXX776287821289", "BOOKXXXX776514515608", "BOOKXXXX774051532082", 
    "BOOKXXXX774051532082"), V2 = c("ZUSRXXXX842901236553", 
    "ZUSRXXXX371255229634", 
     "ZUSRXXXX656080986411", "ZUSRXXXX371255229634", "ZUSRXXXX842901236553", 
    "ZUSRXXXX842901236553"), V3 = c("BOOKEVTX776757835463", 
    "BOOKEVTX776762775464", 
    "BOOKEVTX776772854465", "BOOKEVTX776773643466", "", "BOOKEVTX776995487467"
    ), V4 = c("ZACTIONX215229995154", "ZACTIONX533300043134", 
    "ZACTIONX533300043134", 
    "ZACTIONX533300043134", "", "ZACTIONX215229995154"), V5 = c("", 
    "", "", "", "", ""), V6 = c("", "", "", "", "MAILOUTX776774376684", 
    ""), V7 = c("", "", "", "", "", ""), V8 = c("", "", "", "", "", 
    ""), V9 = c("", "", "", "", "", ""), V10 = c("", "", "", "", 
    "", ""), V11 = c("", "", "", "", "", "")), .Names = c("zkf_BOOK", 
    "V2", "V3", "V4", "V5", "V6", "V7", "V8", "V9", "V10", "V11"), class = 
    c("data.table", 
    "data.frame"), row.names = c(NA, -6L))

这是我的“真实”数据输入示例:

BOOKXXXX774051532082    ZUSRXXXX842901236553    BOOKEVTX776757835463    ZACTIONX215229995154                            
BOOKXXXX776514515608    ZUSRXXXX371255229634    BOOKEVTX776762775464    ZACTIONX533300043134                            
BOOKXXXX776287821289    ZUSRXXXX656080986411    BOOKEVTX776772854465    ZACTIONX533300043134                            
BOOKXXXX776514515608    ZUSRXXXX371255229634    BOOKEVTX776773643466    ZACTIONX533300043134                            
BOOKXXXX774051532082    ZUSRXXXX842901236553                MAILOUTX776774376684                    
BOOKXXXX774051532082    ZUSRXXXX842901236553    BOOKEVTX776995487467    ZACTIONX215229995154                            
BOOKXXXX776287821289    ZUSRXXXX656080986411    BOOKEVTX777107387468    ZACTIONX533300043134    

和预期的输出

BOOKXXXX774051532082    ZUSRXXXX842901236553|BOOKEVTX776757835463|ZACTIONX215229995154|||||||;ZUSRXXXX842901236553||||MAILOUTX776774376684|||||;ZUSRXXXX842901236553|BOOKEVTX776995487467|ZACTIONX215229995154|||||||
BOOKXXXX776514515608    ZUSRXXXX371255229634|BOOKEVTX776762775464|ZACTIONX533300043134|||||||;ZUSRXXXX371255229634|BOOKEVTX776773643466|ZACTIONX533300043134|||||||
BOOKXXXX776287821289    ZUSRXXXX656080986411|BOOKEVTX776772854465|ZACTIONX533300043134|||||||;ZUSRXXXX656080986411|BOOKEVTX777107387468|ZACTIONX533300043134|||||||

【问题讨论】:

  • 你能dput(head(books))
  • 请提供准确的可重现输入和完整的相应输出。解决问题的方法不是并行化,而是编写更高效的 R 代码。
  • @Airmoi,请将该输出添加到您的帖子中,而不是在 cmets 中。使用“编辑”按钮

标签: r data.table subset parallel-foreach


【解决方案1】:

OP 请求了两个折叠操作:

  1. 对于每一行,将所有列(id 列zkf_BOOK 除外)折叠到一个由| 分隔的数据字段中。
  2. 对于每个zkf_BOOK 组,折叠由; 分隔的行

列内的折叠是通过调用Reduce() 完成的,而跨行的折叠是使用paste() 分组完成的。对于data.tableby = 参数中的列不包含在对.SD 的操作中。

library(data.table)
setDT(books)[, paste(Reduce(function(x, y) paste(x, y, sep = "|"), .SD), collapse = ";"), 
             by = zkf_BOOK]
               zkf_BOOK
1: BOOKXXXX774051532082
2: BOOKXXXX776514515608
3: BOOKXXXX776287821289
                                                                                                                                                                                              V1
1: ZUSRXXXX842901236553|BOOKEVTX776757835463|ZACTIONX215229995154|||||||;ZUSRXXXX842901236553||||MAILOUTX776774376684|||||;ZUSRXXXX842901236553|BOOKEVTX776995487467|ZACTIONX215229995154|||||||
2:                                                   ZUSRXXXX371255229634|BOOKEVTX776762775464|ZACTIONX533300043134|||||||;ZUSRXXXX371255229634|BOOKEVTX776773643466|ZACTIONX533300043134|||||||
3:                                                                                                                         ZUSRXXXX656080986411|BOOKEVTX776772854465|ZACTIONX533300043134|||||||

请注意,与预期结果的差异是由于 dput[head(books)) 仅返回 6 行,而打印的数据输入和预期输出基于 7 行(或更多)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    • 2016-11-11
    • 1970-01-01
    相关资源
    最近更新 更多