Можно ли получить переменные группировки внутри пустой группировки в plyr ddply? - PullRequest
0 голосов
/ 30 апреля 2020

Предположим, у нас есть такие данные:

library(plyr)

#some data
x = data.frame(
  letters = factor(c("a", "c"), levels = letters[1:4])
)

Т.е. у нас есть уровни b и d фактора, которого нет в данных. Мы можем l oop по группам 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

Однако предположим, что мы хотим сделать что-то внутри l oop на основе буквы группа. Мы хотим что-то сделать, когда получим пустую группу b. Тем не менее, мы не знаем, когда мы внутри. Если мы добавим if (nrow(xx)==0) browser(), мы можем посмотреть на xx объект:

[1] letters
<0 rows> (or 0-length row.names)

Но мы не можем сказать, является ли это b или d. Можно ли это выяснить?

1 Ответ

0 голосов
/ 30 апреля 2020

Да, это можно сделать с помощью модного поиска. Чтобы понять это, вызовите browser() внутри l oop и осмотрите окружение на предмет наличия объектов с 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"   

ОК, в них определенно что-то есть. Их можно получить, используя 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
...