Comprueba si el número es entero

106

Me sorprendió saber que R no viene con una función útil para verificar si el número es entero.

is.integer(66) # FALSE

Los archivos de ayuda advierten :

is.integer(x)¡no prueba si x contiene números enteros! Para eso, use round, como en la función is.wholenumber(x)en los ejemplos.

El ejemplo tiene esta función personalizada como "solución alternativa"

is.wholenumber <- function(x, tol = .Machine$double.eps^0.5)  abs(x - round(x)) < tol
is.wholenumber(1) # is TRUE

Si tuviera que escribir una función para verificar los números enteros, suponiendo que no haya leído los comentarios anteriores, escribiría una función que iría en la línea de

check.integer <- function(x) {
    x == round(x)
}

¿Dónde fallaría mi enfoque? ¿Cuál sería tu trabajo si estuvieras en mi hipotético lugar?

Roman Luštrik
fuente
Espero que si round(x)se implementa correctamente, el resultado de aplicarlo a un número entero siempre sería ese número entero ...
Stephen
Eche un vistazo a las preguntas frecuentes en R cran.r-project.org/doc/FAQ/…
Richie Cotton
5
> check.integer (9.0) [1] TRUE no lo es.
Peng Peng
@PengPeng, VitoshKa arregló esto en la respuesta aceptada.
Roman Luštrik
4
Creo que hay una confusión sobre los conceptos matemáticos y computacionales de entero. La función is.integercomprueba el concepto computacional, la check.integerfunción de usuario comprueba el punto de vista matemático.
João Daniel

Respuestas:

126

Otra alternativa es verificar la parte fraccionaria:

x%%1==0

o, si desea verificar dentro de una cierta tolerancia:

min(abs(c(x%%1, x%%1-1))) < tol
James
fuente
1
¿La sugerencia de verificación de tolerancia realmente funciona? x <- 5-1e-8; x%%1da 0.9999999 (lo que implicaría si, tol==1e-5por ejemplo) que nox es un número entero.
Ben Bolker
@BenBolker Buena captura, creo que funciona para perturbaciones positivas. Lo he cambiado a una solución alternativa que debería funcionar.
James
2
@James, creo que debería ser en min(abs(c(x%%1, x%%1-1))) < tollugar de lo abs(min(x%%1, x%%1-1)) < tolcontrario, obtendrás FALSEcualquier número entero ...
Cath
3
¿Qué pasa con as.integer(x) == x? No rechazará 3 o 3.0 como lo is.integer(x)haría, y detectará 3.1.
Gabi
34

Aquí hay una solución que usa funciones más simples y sin trucos:

all.equal(a, as.integer(a))

Además, puede probar un vector completo a la vez, si lo desea. Aquí tienes una función:

testInteger <- function(x){
  test <- all.equal(x, as.integer(x), check.attributes = FALSE)
  if(test == TRUE){ return(TRUE) }
  else { return(FALSE) }
}

Puede cambiarlo para usarlo *applyen el caso de vectores, matrices, etc.

Iterador
fuente
11
Lo último se if elsepodría hacer simplemente isTRUE(test). De hecho, eso es todo lo que necesita para reemplazar la if elsecláusula y las returndeclaraciones, ya que R devuelve automáticamente el resultado de la última evaluación.
Gavin Simpson
7
testInteger(1.0000001)[1] FALSO testInteger(1.00000001)[1] VERDADERO
PatrickT
3
all(a == as.integer(a))soluciona este problema! '
Alex
¡Esto no funciona correctamente! Mira el siguiente contraejemplo: frac_test <- 1 / (1-0.98), all.equal (frac_test, as.integer (frac_test)), isTRUE (all.equal (frac_test, as.integer (frac_test)))
tstudio
11

Leer la documentación en lenguaje R as.integertiene más que ver con cómo se almacena el número que si es prácticamente equivalente a un entero. is.integercomprueba si el número se declara como un entero. Puede declarar un número entero colocando un Ldespués de él.

> is.integer(66L)
[1] TRUE
> is.integer(66)
[1] FALSE

También funciones como rounddevolverán un entero declarado, que es lo que estás haciendo x==round(x). El problema con este enfoque es lo que considera que es prácticamente un número entero. El ejemplo usa menos precisión para probar la equivalencia.

> is.wholenumber(1+2^-50)
[1] TRUE
> check.integer(1+2^-50)
[1] FALSE

Entonces, dependiendo de su aplicación, podría tener problemas de esa manera.

Andrew Redd
fuente
1
La segunda línea dice "as.integer comprueba si el número se declara como un entero". pero estoy bastante seguro de que quisiste decir "es.integer". Es solo una edición de un carácter, por lo que no pude cambiarla fácilmente.
PeterVermont
10

Aquí hay una forma aparentemente confiable:

check.integer <- function(N){
    !grepl("[^[:digit:]]", format(N,  digits = 20, scientific = FALSE))
}

check.integer(3243)
#TRUE
check.integer(3243.34)
#FALSE
check.integer("sdfds")
#FALSE

Esta solución también permite números enteros en notación científica:

> check.integer(222e3)
[1] TRUE
VitoshKa
fuente
1
Esto no me parece muy confiable: check.integer(1e4)es VERDADERO, mientras que check.integer(1e5)es FALSO.
miércoles
5
-1 Esto es peor que is.wholenumber, o cualquiera de las otras soluciones proporcionadas en otras respuestas. Estos no deben ser diferentes: check.integer(1e22); check.integer(1e23). Obviamente, puede cambiar la expresión regular para solucionar este problema, pero este enfoque es terrible. (El comentario proviene de la atribución en el paquete de instalación).
Joshua Ulrich
1
@PatrickT, ya veo. Es el argumento del dígito predeterminado. utilizar format(40, scientific = FALSE, digits = 20)en su lugar. He actualizado la respuesta. Gracias por verlo.
VitoshKa
1
@PatrickT Estás en el ámbito de los errores de redondeo dependientes de la máquina. En ese sentido, mi solución es la misma que la aceptada 1.0000000000000001 == 1L [1] TRUE. Pero mi solución es mejor si ya obtiene un número en forma de cadenacheck.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa
4
¡@VitoshKa le encantó tu respuesta! Aunque hay un punto que se perdió, los números negativos sin puntos decimales también son enteros; modifiqué su código en consecuencia.
Mehrad Mahmoudian
8

Parece que no ve la necesidad de incorporar alguna tolerancia a errores. No sería necesario si todos los enteros vinieran ingresados ​​como enteros, sin embargo, a veces vienen como resultado de operaciones aritméticas que pierden algo de precisión. Por ejemplo:

> 2/49*49
[1] 2
> check.integer(2/49*49)
[1] FALSE 
> is.wholenumber(2/49*49)
[1] TRUE

Tenga en cuenta que esta no es la debilidad de R, todo software de computadora tiene algunos límites de precisión.

Aniko
fuente
3
en caso de que algunas personas no entiendan bien lo que sucedió aquí ... si ingresas como .integer (2/49 * 49) obtienes 1 !! [Por cierto, es muy frustrante que R no presente el resultado del cálculo inicial como 2.0 para representar que el valor tiene algún componente decimal) ver ... stackoverflow.com/questions/1535021/…
John
6

De Hmisc::spss.get:

all(floor(x) == x, na.rm = TRUE)

opción mucho más segura, en mi humilde opinión, ya que "pasa por alto" el problema de precisión de la máquina. Si lo intenta is.integer(floor(1)), lo obtendrá FALSE. Por cierto, su número entero no se guardará como entero si es mayor que el .Machine$integer.maxvalor, que es, por defecto, 2147483647, así que cambie el integer.maxvalor o realice las verificaciones alternativas ...

aL3xa
fuente
1
si x <- sqrt(2)^2, entonces all(floor(x) == x, na.rm = TRUE)regresaFALSE
Corrado
3

Puede usar una condición if simple como:

if(round(var) != var)­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Meru Patil
fuente
1

En R, la función de clase puede determinar si un número es numérico o entero. Generalmente, todos los números se almacenan como numéricos y para definir explícitamente un número como entero, necesitamos especificar 'L' después del número.

Ejemplo:

x <- 1

clase (x)

[1] "numérico"

x <- 1L

clase (x)

[1] "entero"

Espero que esto sea lo que se necesitaba. Gracias :)

Meenansha Sachdeva
fuente
0

[ACTUALIZAR] ============================================= ===============

Con respecto a la respuesta [VIEJA] aquí abajo, descubrí que funcionaba porque puse todos los números en un solo vector atómico; uno de ellos era un personaje, por lo que todos se convierten en personajes.

Si usamos una lista (por lo tanto, la coerción no ocurre) todas las pruebas pasan correctamente menos una:, 1/(1 - 0.98)que sigue siendo un numeric. Esto se debe a que el tolparámetro está por defecto 100 * .Machine$double.epsy ese número está lejos de ser un 50poco menos del doble. Entonces, básicamente, para este tipo de números, ¡ tenemos que decidir nuestra tolerancia!

Entonces, si desea que todas las pruebas se conviertan TRUE, puedeassertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

De todos modos, confirmo que IMO asertivo sigue siendo la mejor solución.

A continuación, un reprex para esta [ACTUALIZACIÓN].

expect_trues_c <- c(
  cl = sqrt(2)^2,
  pp = 9.0,
  t = 1 / (1 - 0.98),
  ar0 = 66L,
  ar1 = 66,
  ar2 = 1 + 2^-50,
  v = 222e3,
  w1 = 1e4,
  w2 = 1e5,
  v2 = "1000000000000000000000000000000000001",
  an = 2 / 49 * 49,
  ju1 = 1e22,
  ju2 = 1e24,
  al = floor(1),
  v5 = 1.0000000000000001 # this is under machine precision!
)

str(expect_trues_c)
#>  Named chr [1:15] "2" "9" "50" "66" "66" "1" "222000" "10000" "1e+05" ...
#>  - attr(*, "names")= chr [1:15] "cl" "pp" "t" "ar0" ...
assertive::is_whole_number(expect_trues_c)
#> Warning: Coercing expect_trues_c to class 'numeric'.
#>                      2                      9                     50 
#>                   TRUE                   TRUE                   TRUE 
#>                     66                     66                      1 
#>                   TRUE                   TRUE                   TRUE 
#>                 222000                  10000                 100000 
#>                   TRUE                   TRUE                   TRUE 
#>                  1e+36                      2                  1e+22 
#>                   TRUE                   TRUE                   TRUE 
#> 9.9999999999999998e+23                      1                      1 
#>                   TRUE                   TRUE                   TRUE



expect_trues_l <- list(
  cl = sqrt(2)^2,
  pp = 9.0,
  t = 1 / (1 - 0.98),
  ar0 = 66L,
  ar1 = 66,
  ar2 = 1 + 2^-50,
  v = 222e3,
  w1 = 1e4,
  w2 = 1e5,
  v2 = "1000000000000000000000000000000000001",
  an = 2 / 49 * 49,
  ju1 = 1e22,
  ju2 = 1e24,
  al = floor(1),
  v5 = 1.0000000000000001 # this is under machine precision!
)

str(expect_trues_l)
#> List of 15
#>  $ cl : num 2
#>  $ pp : num 9
#>  $ t  : num 50
#>  $ ar0: int 66
#>  $ ar1: num 66
#>  $ ar2: num 1
#>  $ v  : num 222000
#>  $ w1 : num 10000
#>  $ w2 : num 1e+05
#>  $ v2 : chr "1000000000000000000000000000000000001"
#>  $ an : num 2
#>  $ ju1: num 1e+22
#>  $ ju2: num 1e+24
#>  $ al : num 1
#>  $ v5 : num 1
assertive::is_whole_number(expect_trues_l)
#> Warning: Coercing expect_trues_l to class 'numeric'.
#> There was 1 failure:
#>   Position              Value      Cause
#> 1        3 49.999999999999957 fractional
assertive::is_whole_number(expect_trues_l, tol = 200 * .Machine$double.eps)
#> Warning: Coercing expect_trues_l to class 'numeric'.
#>     2.0000000000000004                      9     49.999999999999957 
#>                   TRUE                   TRUE                   TRUE 
#>                     66                     66     1.0000000000000009 
#>                   TRUE                   TRUE                   TRUE 
#>                 222000                  10000                 100000 
#>                   TRUE                   TRUE                   TRUE 
#>                  1e+36     1.9999999999999998                  1e+22 
#>                   TRUE                   TRUE                   TRUE 
#> 9.9999999999999998e+23                      1                      1 
#>                   TRUE                   TRUE                   TRUE



expect_falses <- list(
  bb = 5 - 1e-8,
  pt1 = 1.0000001,
  pt2 = 1.00000001,
  v3 = 3243.34,
  v4 = "sdfds"
)

str(expect_falses)
#> List of 5
#>  $ bb : num 5
#>  $ pt1: num 1
#>  $ pt2: num 1
#>  $ v3 : num 3243
#>  $ v4 : chr "sdfds"
assertive::is_whole_number(expect_falses)
#> Warning: Coercing expect_falses to class 'numeric'.
#> Warning in as.this_class(x): NAs introduced by coercion
#> There were 5 failures:
#>   Position              Value      Cause
#> 1        1 4.9999999900000001 fractional
#> 2        2 1.0000001000000001 fractional
#> 3        3 1.0000000099999999 fractional
#> 4        4 3243.3400000000001 fractional
#> 5        5               <NA>    missing
assertive::is_whole_number(expect_falses, tol = 200 * .Machine$double.eps)
#> Warning: Coercing expect_falses to class 'numeric'.

#> Warning: NAs introduced by coercion
#> There were 5 failures:
#>   Position              Value      Cause
#> 1        1 4.9999999900000001 fractional
#> 2        2 1.0000001000000001 fractional
#> 3        3 1.0000000099999999 fractional
#> 4        4 3243.3400000000001 fractional
#> 5        5               <NA>    missing

Creado el 2019-07-23 por el paquete reprex (v0.3.0)

[ANTIGUO] ============================================= ==================

En mi opinión, la mejor solución proviene del assertivepaquete (que, por el momento, resuelve todos los ejemplos positivos y negativos en este hilo):

are_all_whole_numbers <- function(x) {
  all(assertive::is_whole_number(x), na.rm = TRUE)
}

are_all_whole_numbers(c(
  cl = sqrt(2)^2,
  pp = 9.0,
  t = 1 / (1 - 0.98),
  ar0 = 66L,
  ar1 = 66,
  ar2 = 1 + 2^-50,
  v = 222e3,
  w1 = 1e4,
  w2 = 1e5,
  v2 = "1000000000000000000000000000000000001",
  an = 2 / 49 * 49,
  ju1 = 1e22,
  ju2 = 1e24,
  al = floor(1),
  v5 = 1.0000000000000001 # difference is under machine precision!
))
#> Warning: Coercing x to class 'numeric'.
#> [1] TRUE

are_all_not_whole_numbers <- function(x) {
  all(!assertive::is_whole_number(x), na.rm = TRUE)
}

are_all_not_whole_numbers(c(
  bb = 5 - 1e-8,
  pt1 = 1.0000001,
  pt2 = 1.00000001,
  v3 = 3243.34,
  v4 = "sdfds"
))
#> Warning: Coercing x to class 'numeric'.
#> Warning in as.this_class(x): NAs introduced by coercion
#> [1] TRUE

Creado el 2019-07-23 por el paquete reprex (v0.3.0)

Corrado
fuente
0

Once también puede usar dplyr::near:

library(dplyr)

near(a, as.integer(a))

Se aplica a cualquier vector ay tiene un parámetro de tolerancia opcional.

James Hirschorn
fuente
-3

No estoy seguro de lo que está tratando de lograr. Pero aquí hay algunas ideas:
1. Convierta a un número entero:
num = as.integer(123.2342)
2. Compruebe si una variable es un número entero:
is.integer(num)
typeof(num)=="integer"

bernardw
fuente
Solo me aseguro de que los usuarios ingresen un número apropiado; estamos hablando del número de "sujetos", que puede ser solo un número entero.
Roman Luštrik