2

我正在转换本地 R 脚本以使用RevoScaleRRevolution-R(又名 Microsoft R 客户端/服务器)包中的功能。这是为了能够更好地处理大量数据。

目标是创建一个新列,为每组的行编号。使用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

在使用 -functions 进行一些研究后,rx我找到了 package dplyrXdf,它基本上是一个dplyr在存储数据上使用函数的包装器Xdf,同时仍然受益于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.

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

4

3 回答 3

2

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

请注意,这n()不是一个常规的 R 函数,尽管它看起来像一个。它需要为每个数据源专门实现,也可能分别为每个mutate,summarisefilter.

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

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

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

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))

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

于 2016-08-25T07:47:25.030 回答
1

我不确定为什么会这样,但请尝试使用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)
于 2016-08-22T17:57:35.647 回答
0

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)
于 2016-08-18T23:44:25.117 回答