假设我们有这样的数据。
library(plyr)
#some data
x = data.frame(
letters = factor(c("a", "c"), levels = letters[1:4])
)
也就是说,我们有一个因子的b和d级,但在数据中没有出现。我们可以循环处理 letters
:
#loop inside
plyr::ddply(x, "letters", function(xx) {
#do something here
if (xx$letters == "b") print("do something")
data.frame(
count = nrow(xx)
)
})
给我们。
letters count
1 a 1
2 c 1
所以我们漏掉了b和d两级。然后我们加上 drop = F
以免跳过它们。
plyr::ddply(x, "letters", .drop = F, function(xx) {
#do something here
#if (xx$letters == "b") print("do something")
data.frame(
count = nrow(xx)
)
})
我们得到。
letters count
1 a 1
2 b 0
3 c 1
4 d 0
然而,假设我们想在循环中做一些基于字母组的事情。当我们得到空b组时,我们想做一些事情。然而,我们不知道我们什么时候在里面。如果我们添加 if (nrow(xx)==0) browser()
,我们可以看看 xx
对象。
[1] letters
<0 rows> (or 0-length row.names)
但我们无法判断它是b还是d. 有可能找到吗?
是的,可以通过花式查找来实现。要弄清楚,请调用 browser()
的对象,并在循环中检查环境中是否有带有 ls()
:
Called from: .fun(piece, ...)
Browse[1]> c
Called from: .fun(piece, ...)
Browse[1]> xx
[1] letters
<0 rows> (or 0-length row.names)
Browse[1]> ls(all.names = T)
[1] "xx"
因此,这里除了空的数据框架部分(原始数据的子集)外,什么都没有。如果这里有一个隐藏的对象来表明这块数据,那就更好了,但可惜。不过,我们可以看看父环境,看看是否幸运。
Browse[1]> ls(all.names = T, envir = parent.frame(1))
[1] "i" "piece"
Browse[1]> ls(all.names = T, envir = parent.frame(2))
[1] "..." ".data" ".fun" ".inform" ".parallel" ".paropts" ".progress" "do.ply" "n" "pieces" "progress"
[12] "result"
OK,其中肯定有一些东西。我们可以用以下方法来获取这些 get()
或 mget()
为一次多个。
Browse[1]> mget(ls(envir = parent.frame(1)), envir = parent.frame(1))
$i
[1] 2
$piece
[1] letters
<0 rows> (or 0-length row.names)
Browse[1]> mget(ls(envir = parent.frame(2)), envir = parent.frame(2))
$do.ply
function (i)
{
piece <- pieces[[i]]
if (.inform) {
res <- try(.fun(piece, ...))
if (inherits(res, "try-error")) {
piece <- paste(utils::capture.output(print(piece)),
collapse = "\n")
stop("with piece ", i, ": \n", piece, call. = FALSE)
}
}
else {
res <- .fun(piece, ...)
}
progress$step()
res
}
<bytecode: 0x559669467ca8>
<environment: 0x55966c7c6798>
$n
[1] 4
$pieces
$a
letters
1 a
$b
[1] letters
<0 rows> (or 0-length row.names)
$c
letters
1 c
$d
[1] letters
<0 rows> (or 0-length row.names)
$progress
$progress$init
function (x)
NULL
<bytecode: 0x559669453cd0>
<environment: 0x55966e5c8b50>
$progress$step
function ()
NULL
<bytecode: 0x559669453e58>
<environment: 0x55966e5c8b50>
$progress$term
function ()
NULL
<bytecode: 0x559669453e58>
<environment: 0x55966e5c8b50>
$result
$result[[1]]
NULL
$result[[2]]
NULL
$result[[3]]
NULL
$result[[4]]
NULL
所以我们看到 i
在 parent.frame(1)
是当前子集的数量,而在 parent.frame(2)
有我们想要的等级。把它们放在一起,我们可以得到当前的等级。
plyr::ddply(x, "letters", .drop = F, function(xx) {
#figure out the piece
i = get("i", envir = parent.frame(1))
levels = names(get("pieces", envir = parent.frame(1)))
current_piece = levels[i]
#do something
if (current_piece == "b") print("this is the b empty group!") else print("This is not level b")
data.frame(
count = nrow(xx)
)
})
结果是:
[1] "This is not level b"
[1] "this is the b empty group!"
[1] "This is not level b"
[1] "This is not level b"
letters count
1 a 1
2 b 0
3 c 1
4 d 0