使用RevoScaleR的每个组的行数

时间:2016-08-15 12:24:42

标签: r revolution-r

我正在转换本地R脚本以使用Revolution-R(又名Microsoft R Client / Server)包中的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 - 函数进行一些研究之后,我找到了包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.

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

3 个答案:

答案 0 :(得分:2)

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

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

目前,xdf文件支持n的唯一用法是在summarise内,以计算行数。为其他动词实现它实际上是非常重要的。

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

获取正确序列号的方法是保持您为该组读取的行数的运行计数,并在每次处理块时更新它。您可以使用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))

这适用于locallocalparforeach计算上下文。它可能不起作用(或者至少不会给出可重现的结果)任何上下文,你不能保证rxDataStep将以确定的顺序处理行 - 所以Mapreduce,Spark,Teradata或类似的。

答案 1 :(得分: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)

答案 2 :(得分: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)