Estou usando a função ifelse()
para manipular um vetor de data. Eu esperava que o resultado fosse de classe Date
e fiquei surpreso ao obter um numeric
vetor. Aqui está um exemplo:
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
dates <- ifelse(dates == '2011-01-01', dates - 1, dates)
str(dates)
Isso é especialmente surpreendente porque a execução da operação em todo o vetor retorna um Date
objeto.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
Devo estar usando alguma outra função para operar em Date
vetores? Se sim, qual função? Caso contrário, como forço ifelse
a retornar um vetor do mesmo tipo que a entrada?
A página de ajuda para ifelse
indica que esse é um recurso, não um bug, mas ainda estou lutando para encontrar uma explicação para o que achei um comportamento surpreendente.
r
datetime
if-statement
Zach
fonte
fonte
if_else()
no pacote dplyr que pode substituirifelse
, mantendo as classes corretas dos objetos Date - ela é postada abaixo como resposta recente. Estou chamando a atenção aqui, pois resolve esse problema, fornecendo uma função que é testada em unidade e documentada em um pacote CRAN, diferente de muitas outras respostas que (a partir deste comentário) foram classificadas à frente.Respostas:
Você pode usar
data.table::fifelse
(data.table >= 1.12.3
) oudplyr::if_else
.data.table::fifelse
dplyr::if_else
De
dplyr 0.5.0
notas de versão :fonte
true
's efalse
' s.if_else
be NA? Eu tenho tentado as lógicasNA_
opções e nada está furando e eu não acredito que há umaNA_double_
NA
-seas.Date
.NA_real_
, @roarkz. e @ Henrik, seu comentário aqui resolveu meu problema.Está relacionado ao valor documentado de
ifelse
:Resumindo, suas implicações
ifelse
fazem com que os fatores percam seus níveis e as Datas percam sua classe e apenas seu modo ("numérico") é restaurado. Tente isso:Você pode criar um
safe.ifelse
:Uma observação posterior: vejo que Hadley incorporou um
if_else
complexo magrittr / dplyr / tidyr de pacotes de modelagem de dados.fonte
safe.ifelse <- function(cond, yes, no) structure(ifelse(cond, yes, no), class = class(yes))
ifelse()
não é "seguro" .A explicação de DWin está no local. Eu brinquei e lutei com isso por um tempo antes de perceber que poderia simplesmente forçar a classe após a declaração ifelse:
No começo, isso me pareceu um pouco "tolo". Mas agora eu penso nisso como um pequeno preço a pagar pelos retornos de desempenho que recebo da ifelse (). Além disso, ainda é muito mais conciso do que um loop.
fonte
for
cessionários declaração do valor dos itens emVECTOR
queNAME
, mas não a sua classe .O método sugerido não funciona com colunas de fatores. Gostaria de sugerir esta melhoria:
A propósito: ifelse é uma merda ... com grande poder, vem uma grande responsabilidade, ou seja, conversões de tipo de matrizes 1x1 e / ou numéricos [quando elas devem ser adicionadas por exemplo] é aceitável para mim, mas essa conversão de tipo em ifelse é claramente indesejada. Eu encontrei o mesmo 'bug' do ifelse várias vezes agora e ele continua roubando meu tempo :-(
FW
fonte
yes
eno
e que você primeiro verificaria se ambos eram fatores. Você provavelmente precisaria converter para caractere e depois reorganizar com os níveis "sindicalizados".A razão pela qual isso não funciona é porque, a função ifelse () converte os valores em fatores. Uma boa solução seria convertê-lo em caracteres antes de avaliá-lo.
Isso não exigiria nenhuma biblioteca além da base R.
fonte
A resposta fornecida por @ fabian-werner é ótima, mas os objetos podem ter várias classes e "fator" pode não ser necessariamente o primeiro retornado por
class(yes)
, então sugiro esta pequena modificação para verificar todos os atributos de classe:Também enviei uma solicitação com a equipe de desenvolvimento do R para adicionar uma opção documentada para ter atributos base :: ifelse () preserve com base na seleção do usuário de quais atributos preservar. A solicitação está aqui: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - Ela já foi sinalizada como "WONTFIX", alegando que sempre foi dessa maneira, mas forneci um argumento de acompanhamento sobre por que uma simples adição pode economizar muitas dores de cabeça dos usuários do R. Talvez o seu "+1" nesse segmento de bug incentive a equipe do R Core a dar uma segunda olhada.
EDIT: Aqui está uma versão melhor que permite ao usuário especificar quais atributos preservar, "cond" (comportamento padrão ifelse ()), "yes", o comportamento conforme o código acima ou "no", nos casos em que o atributos do valor "no" são melhores:
fonte
inherits(y, "factor")
pode ser "mais correto" do que"factor" %in% class.y
inherits
pode ser melhor.