Почему sapply() возвращает список?
Я столкнулся с необычным поведением в R с помощью функции sapply()
. Эта функция должна возвращать вектор, но в специальном случае, когда вы даете ему пустой вектор, он возвращает список.
Правильное поведение с вектором:
a = c("A", "B", "C")
a[a == "B"] # Returns "B"
a[sapply(a, function(x) {x == "B"})] # Returns "B"
Правильное поведение со значением NULL:
a = NULL
a[a == "B"] # Returns NULL
a[sapply(a, function(x) {x == "B"})] # Returns NULL
Странное поведение с пустым вектором:
a = vector()
a[a == "B"] # Returns NULL
a[sapply(a, function(x) {x == "B"})] # Erreur : type 'list' d'indice incorrect
Такое же сообщение об ошибке, что и в этом выражении:
a[list()] # Erreur dans a[list()] : type 'list' d'indice incorrect
Почему? Это ошибка?
Из-за этого странного поведения я использую unlist(lapply())
.
Ответы
Ответ 1
Настоящая причина в том, что sapply
не знает, что ваша функция вернется, не вызвав ее. В вашем случае функция возвращает logical
, но поскольку sapply
задан пустой список, функция никогда не вызывается. Следовательно, он должен иметь тип и по умолчанию равен list
.
... Именно по этой причине (и для производительности) был введен vapply
! Он требует указать тип возвращаемого значения (и длину). Это позволяет делать правильные вещи. В качестве бонуса это также быстрее!
sapply(LETTERS[1:3], function(x) {x == "B"}) # F, T, F
sapply(LETTERS[0], function(x) {x == "B"}) # list()
vapply(LETTERS[1:3], function(x) {x == "B"}, logical(1)) # F, T, F
vapply(LETTERS[0], function(x) {x == "B"}, logical(1)) # logical()
Подробнее см. ?vapply
.
Ответ 2
Справка для функции ?sapply
имеет это в разделе Значение
For ‘sapply(simplify = TRUE)’ and ‘replicate(simplify = TRUE)’: if
‘X’ has length zero or ‘n = 0’, an empty list.
В обоих случаях:
> length(NULL)
[1] 0
> length(vector())
[1] 0
Следовательно, sapply()
возвращает:
> sapply(vector(), function(x) {x == "B"})
list()
> sapply(NULL, function(x) {x == "B"})
list()
Ваша ошибка не от sapply()
, а от [
, как показано на рисунке:
> a[list()]
Error in a[list()] : invalid subscript type 'list'
Таким образом, проблема связана с тем, как выполняется подмножество NULL
и пустой вектор (vector()
). Ничего общего с sapply()
. В обоих случаях он возвращает согласованный вывод, пустой список.
Ответ 3
На самом деле оба они возвращают list
. Единственное различие между ними заключается в том, что когда вы пытаетесь индексировать NULL
, он всегда возвращает NULL (даже если ваш индекс был списком), но когда вы пытаетесь индексировать пустой вектор, он проверяет индекс и понимает, что это list
.
a = NULL
res = sapply(a, function(x) x == "B") # Res is an empty list
a[res] # returns NULL, because any index of NULL is NULL.
a = vector()
res = sapply(a, function(x) x == "B") # Still an empty list.
a[res] # but you can't index a vector with a list!