Qual é o comportamento exato do dplyr se o usuário chamar select() em vez de filter() com uma expressão de filtro de linha?(Peguei vocês)
-
21-12-2019 - |
Pergunta
dplyr deixa passar silenciosamente se um usuário ligar por engano select()
em um tbl_df com uma expressão de filtro de linha, em vez de filter()
.
Como exatamente select()
avalia uma expressão de filtro de linha (não deve ter sentido) e por que ela é avaliada como sempre VERDADEIRA?Em vez de FALSE, o que ajudaria a capturar o erro (e/ou gerar o aviso 'Aviso:select() recebeu expressão sem sentido'), ambos seriam um comportamento melhor?
require(dplyr)
set.seed(1234)
df <- tbl_df(data.frame(u=sample.int(3,10,replace=T), v=sample.int(4,10,replace=T)))
df %.% select(u!=3 & v>=3) # NONSENSE! silently passes all rows of df!
df %.% filter(u!=3 & v>=3) # CORRECT: filters only the 4 rows specified
u v
1 1 3
2 2 3
3 2 4
4 2 4
u v
1 2 3
2 1 3
3 1 2
4 2 3
5 1 2
6 3 3
7 1 3
8 1 2
9 3 1
10 3 4
Solução
Você pode dar uma olhada na fonte código.
Para entender completamente o que está acontecendo, vamos fazer debug(select_vars_q)
então corra df %.% select(u!=3 & v>=3)
.
As variáveis vars
e args
são
Browse[2]> vars
[1] "u" "v"
Browse[2]> args
[[1]]
u != 3 & v >= 3
A seguir, consideramos apenas as linhas que estão relacionadas a args
.Por exemplo, na linha 107
debug: ind_list <- lapply(args, eval, env = select_env)
Browse[2]> lapply(args, eval, env = select_env)
[[1]]
[1] FALSE
Esta linha é usada quando args
é starts_with
, ends_with
,...etc.(ver 67) e retornará o número do índice da variável com base em args
.
No nosso caso, o valor retornado é FALSE
qual é 0
(por que?desde 61 implica u=1
e v=2
), portanto, não corresponde a nenhuma variável, então este linha irá garantir que todas as colunas serão retornadas quando nada for correspondido.
Para confirmar minha análise, vamos executar este comando confuso df %.% select(u=2)
, De acordo com a análise acima, ind_list
vai ser 2
, significa que a coluna 2 será retornada.E o resultado:
> df %.% select(u=2)
Source: local data frame [10 x 1]
u
1 3
2 3
3 2
4 4
5 2
6 4
7 2
8 2
9 1
10 1
Sim, é a 2ª coluna.!
Em resumo, se o argumento de select não for starts_with
, ends_with
...etc, e quando o argumento for um número (ou puder ser avaliado como um número), esse número será interpretado como o número da coluna.
Por exemplo, df %.% select(1)
retorna a primeira coluna e df %.% select(2)
retorna a 2ª coluna.