能否在plyr ddply中获取空分组内的分组变量?

问题描述 投票:0回答:1

假设我们有这样的数据。

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. 有可能找到吗?

r plyr
1个回答
0
投票

是的,可以通过花式查找来实现。要弄清楚,请调用 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

所以我们看到 iparent.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
© www.soinside.com 2019 - 2024. All rights reserved.