【问题标题】:Number rows per group with RevoScaleR使用 RevoScaleR 每组的行数
【发布时间】:2016-08-15 12:24:42
【问题描述】:

我正在转换本地 R 脚本以使用 Revolution-R(又名 Microsoft R 客户端/服务器)包中的 RevoScaleR 函数。这样可以更好地处理大量数据。

目标是创建一个新列,为每组的行编号。使用data.table 可以使用以下代码实现:

library(data.table)
eventlog[,ActivityNumber := seq(from=1, to=.N, by=1), by=Case.ID]

出于说明目的,输出如下所示:

    Case.ID    ActivityNumber
1       A              1
2       A              2
3       B              1
4       C              1
5       C              2
6       C              3

在使用rx-functions 进行一些研究后,我找到了包dplyrXdf,它基本上是在Xdfstored 数据上使用dplyrfunctions 的包装器,同时仍然受益于优化的功能RevoScaleR(见http://blog.revolutionanalytics.com/2015/10/using-the-dplyrxdf-package.html

就我而言,这将导致以下结果:

result <- eventlog %>%
  group_by(Case.ID) %>%
  mutate(ActivityNumber = seq_len(n()))

但是,这会导致以下错误:

ERROR: Attempting to add a variable without a name to an analysis.
Caught exception in file: CxAnalysis.cpp, line: 3756. ThreadID: 1248 Rethrowing.
Caught exception in file: CxAnalysis.cpp, line: 5249. ThreadID: 1248 Rethrowing.
Error in doTryCatch(return(expr), name, parentenv, handler) : 
  Error in executing R code: ERROR: Attempting to add a variable without a name to an analysis.

任何想法如何解决这个错误?或者其他(更好的?)方法来获得请求的结果?

【问题讨论】:

    标签: r revolution-r


    【解决方案1】:

    感谢@Matt-parker 向我指出这个问题。

    请注意,n() 不是常规的 R 函数,尽管它看起来像一个。它需要针对每个数据源专门实现,也可能针对mutatesummarisefilter中的每一个单独实现。

    目前,xdf 文件支持的n 的唯一用法是在summarise 内,用于计算行数。为其他动词实现它实际上并不简单。

    特别是,Matt 使用seq_along 来实现n 的功能存在问题。请记住,xdf 文件是块结构的:每个行块的读取和处理独立于其他块。这意味着生成的序列仅针对该行块,而不是针对组中的所有行。如果一个组跨越多个块,则序列号将在中间重新开始。

    获得正确序列号的方法是持续计算您已为该组读取的行数,并在每次处理块时更新它。您可以使用transformFunc 来执行此操作,您可以通过.rxArgs 参数将其传递给transmute

    ev <- eventlog %>% group_by(Case.ID) %>% transmute(.rxArgs = list(
        transformFunc = function(varList) {
            n <- .n + seq_along(varList[[1]])
            if(!.rxIsTestChunk)  # need this b/c rxDataStep does a test run on the 1st 10 rows
                .n <<- n[length(n)]
            list(n=n)
        },
        transformObjects = list(.n = 0))
    

    这应该适用于locallocalparforeach 计算上下文。在您无法保证 rxDataStep 以确定性顺序处理行的任何上下文中,它可能无法工作(或至少不会给出可重现的结果)——例如 Mapreduce、Spark、Teradata 或类似的。

    【讨论】:

      【解决方案2】:

      我不确定为什么会这样,但请尝试使用 seq_along(Case.ID) 而不是 seq_len(n())

      result <- eventlog %>%
        group_by(Case.ID) %>%
        mutate(ActivityNumber = seq_along(Case.ID))
      

      n() 似乎有问题。这是我的探索性代码,以防其他人想尝试:

      options(stringsAsFactors = FALSE)
      
      library(dplyrXdf)
      
      # Set up some test data
      eventlog_df <- data.frame(Case.ID = c("A", "A", "A", "A", "A", "B", "C", "C", "C"))
      
      # Add a variable for artificially splitting the XDF into small chunks
      eventlog_df$Chunk.ID <- factor((seq_len(nrow(eventlog_df)) + 2) %/% 3)
      
      # Check the results
      eventlog_df
      
      
      # Now read it into an XDF file. I'm going to read just three rows in at a time
      # so that the XDF file has several chunks, so we can be confident this works
      # across chunks
      
      eventlog <- tempfile(fileext = ".xdf")
      
      for(i in 1:3) {
          rxImport(inData = eventlog_df[eventlog_df$Chunk.ID %in% i, ],
                   outFile = eventlog,
                   colInfo = list(Case.ID = list(type = "factor", 
                                                 levels = c("A", "B", "C"))),
                   append = file.exists(eventlog))
      }
      
      # Convert to a proper data source
      eventlog <- RxXdfData(eventlog)
      
      rxGetInfo(eventlog, getVarInfo = TRUE, numRows = 10)
      
      
      # Now to dplyr. First, let's make sure it can count up the records
      # in each group without any trouble.
      result <- eventlog %>%
        group_by(Case.ID) %>%
        summarise(ActivityNumber = n())
      
      # It can:
      rxDataStep(result)
      
      
      # Now if we switch to mutate, does n() still work?
      result <- eventlog %>%
        group_by(Case.ID) %>%
        mutate(ActivityNumber = n())
      
      # No - and it seems to be complaining about missing variables. So what if
      # we try to refer to a variable we *know* exists?
      result <- eventlog %>%
        group_by(Case.ID) %>%
        mutate(ActivityNumber = seq_along(Case.ID))
      
      # It works
      rxDataStep(result)
      

      【讨论】:

      • 确实有效。奇怪的是,它有时会在更大的数据集上失败(给出与 n() 完全相同的错误)。我不知道是 dplyrXdf 是罪魁祸首,还是别的什么……
      【解决方案3】:

      dplyrdplyrXdf 有一个 tally 方法来计算每组的项目数:

      result <- eventlog %>%
        group_by(Case.ID) %>%
        tally()
      

      如果您想做的不仅仅是将每组的记录制成表格,您可以使用汇总(因为您没有显示您的数据,我使用了一个名为延迟的假设列,我假设它是用于说明的数字目的):

      result <- eventlog %>%
        group_by(Case.ID) %>%
        summarize(counts = n(),
                  ave_delay = mean(delay))
      

      您可以使用常规的RevoScaleR 函数完成上述操作,

      rxCrossTabs(~ Case.ID, data = eventlog)
      

      第二个例子:

      rxCube(delay ~ Case.ID, data = eventlog)
      

      【讨论】:

      • 感谢您对此进行调查,但这并不能回答我的问题。我不想获得每组的记录总数,我想为每组的记录编号。从 data.table 查看所需的输出。 group_by 仅用于评估编号应从 0 重新开始的位置。
      猜你喜欢
      • 1970-01-01
      • 2021-03-14
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多