我正在转换本地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.
任何想法如何解决此错误?或其他(更好?)方法来获得所要求的结果?
答案 0 :(得分:2)
感谢@ Matt-parker指点我这个问题。
请注意,n()
不是常规的R函数,尽管它看起来像一个。它需要专门为每个数据源实现,也可能分别为mutate
,summarise
和filter
中的每一个实现。
目前,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))
这适用于local
,localpar
和foreach
计算上下文。它可能不起作用(或者至少不会给出可重现的结果)任何上下文,你不能保证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)
dplyr
和dplyrXdf
使用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)