Estou tentando testar se todos os elementos de um vetor são iguais uns aos outros. As soluções que encontrei parecem um tanto indiretas, ambas envolvendo verificação length()
.
x <- c(1, 2, 3, 4, 5, 6, 1) # FALSE
y <- rep(2, times = 7) # TRUE
Com unique()
:
length(unique(x)) == 1
length(unique(y)) == 1
Com rle()
:
length(rle(x)$values) == 1
length(rle(y)$values) == 1
Uma solução que me permitisse incluir um valor de tolerância para avaliar a 'igualdade' entre os elementos seria ideal para evitar os problemas da FAQ 7.31 .
Existe uma função integrada para o tipo de teste que eu ignorei completamente? identical()
e all.equal()
compare dois objetos R, então eles não funcionarão aqui.
Editar 1
Aqui estão alguns resultados de benchmarking. Usando o código:
library(rbenchmark)
John <- function() all( abs(x - mean(x)) < .Machine$double.eps ^ 0.5 )
DWin <- function() {diff(range(x)) < .Machine$double.eps ^ 0.5}
zero_range <- function() {
if (length(x) == 1) return(TRUE)
x <- range(x) / mean(x)
isTRUE(all.equal(x[1], x[2], tolerance = .Machine$double.eps ^ 0.5))
}
x <- runif(500000);
benchmark(John(), DWin(), zero_range(),
columns=c("test", "replications", "elapsed", "relative"),
order="relative", replications = 10000)
Com os resultados:
test replications elapsed relative
2 DWin() 10000 109.415 1.000000
3 zero_range() 10000 126.912 1.159914
1 John() 10000 208.463 1.905251
Portanto, parece que diff(range(x)) < .Machine$double.eps ^ 0.5
é o mais rápido.
system.time(for(i in 1:1e4) zero_range(x))
, de ondex
vinha o OP. A solução de John é ~ 10x parax
, ~ 3x mais rápida paray
e ligeiramente mais lenta pararunif(1e6)
.Por que não simplesmente usar a variação:
Se todos os elementos de
x
forem iguais, você obterá uma variação de0
.fonte
length(unique(x))=1
acaba sendo duas vezes mais rápido, masvar
é conciso, o que é bom.John test: TRUE ; DWin test: TRUE ; zero-range test: TRUE ; variance test: FALSE
que todos os outros testes reconhecem que os valores são idênticos em R. Como o teste de variância pode ser usado nesse contexto?TRUE
? No caso da resposta de John, você verifica se a diferença está acima de um certo limite. No seu caso, a diferença entre os 2 valores é muito baixa, o que pode fazer com que fique abaixo do limite definido.Se forem todos valores numéricos, se tol for sua tolerância, então ...
é a solução para o seu problema.
EDITAR:
Depois de olhar para esta e outras respostas, e comparar algumas coisas, o seguinte sai duas vezes mais rápido que a resposta DWin.
Isso é um pouco surpreendentemente mais rápido,
diff(range(x))
jádiff
que não deve ser muito diferente de-
eabs
com dois números. Solicitar o intervalo deve otimizar a obtenção do mínimo e máximo. Ambosdiff
erange
são funções primitivas. Mas o momento não mente.fonte
Outro na mesma linha:
fonte
x <- seq(1, 10) / 1e10
Você pode usar
identical()
eall.equal()
comparando o primeiro elemento com todos os outros, varrendo efetivamente a comparação:Dessa forma, você pode adicionar qualquer épsilon
identical()
conforme necessário.fonte
Você pode apenas verificar
all(v==v[1])
fonte
NA
em seu vetor:x <- c(1,1,NA); all(x == x[1])
retornaNA
, nãoFALSE
. Em tais casos,length(unique(x)) == 1
funciona.Como sempre volto a essa pergunta, aqui está uma
Rcpp
solução que geralmente será muito mais rápida do que qualquer uma dasR
soluções se a resposta for realmenteFALSE
(porque ela irá parar no momento em que encontra uma incompatibilidade) e terá a mesma velocidade como a solução R mais rápida se a resposta forTRUE
. Por exemplo, para o benchmark OP,system.time
clica em exatamente 0 usando esta função.fonte
fast_equal(c(2,1,3), 1.5)
a == b
,b == c
não significa necessariamentea == c
que você esteja fazendo comparações de ponto flutuante. Você pode dividir a sua precisão pelo número de elementos a evitar esse problema, ou modificar o algoritmo para calcularmin
emax
e usando isso como uma condição de parada.Escrevi uma função especificamente para isso, que pode verificar não apenas os elementos em um vetor, mas também pode verificar se todos os elementos de uma lista são idênticos . É claro que também lida com vetores de caracteres e todos os outros tipos de vetores. Ele também possui tratamento de erros apropriado.
Agora tente alguns exemplos.
fonte
Na verdade, você não precisa usar min, mean ou max. Com base na resposta de John:
fonte
Aqui está uma alternativa usando o truque mínimo e máximo, mas para um quadro de dados. No exemplo, estou comparando colunas, mas o parâmetro de margem de
apply
pode ser alterado para 1 para linhas.Se
valid == 0
todos os elementos forem iguaisfonte