Controlla se il numero è intero


105

Sono stato sorpreso di apprendere che R non viene fornito con una funzione utile per verificare se il numero è intero.

is.integer(66) # FALSE

I file della guida avvertono :

is.integer(x)non verifica se x contiene numeri interi! Per questo, usa round, come nella funzione is.wholenumber(x)negli esempi.

L'esempio ha questa funzione personalizzata come "soluzione alternativa"

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

Se dovessi scrivere una funzione per verificare la presenza di numeri interi, supponendo di non aver letto i commenti sopra, scriverei una funzione che andrebbe sulla falsariga di

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

Dove fallirebbe il mio approccio? Quale sarebbe il tuo lavoro se fossi nei miei ipotetici panni?


Spero che se round(x)viene implementato correttamente, il risultato dell'applicazione a un numero intero sarebbe sempre quel numero intero ...
Stephen

Dai un'occhiata alle FAQ su R cran.r-project.org/doc/FAQ/…
Richie Cotton

5
> check.integer (9.0) [1] TRUE non lo è.
Peng Peng

@PengPeng, VitoshKa ha risolto questo problema nella risposta accettata.
Roman Luštrik

4
Penso che ci sia una confusione sui concetti matematici e computazionali di intero. La funzione is.integerverifica il concetto computazionale, la check.integerfunzione utente verifica il punto di vista matematico.
João Daniel

Risposte:


126

Un'altra alternativa è controllare la parte frazionaria:

x%%1==0

oppure, se vuoi controllare entro una certa tolleranza:

min(abs(c(x%%1, x%%1-1))) < tol

1
il suggerimento per il controllo della tolleranza funziona davvero? x <- 5-1e-8; x%%1fornisce 0.9999999 (che implicherebbe se tol==1e-5per esempio) che nonx è un numero intero.
Ben Bolker

@BenBolker Buona presa, funziona per perturbazioni positive credo. L'ho cambiato in una soluzione alternativa dovrebbe funzionare.
James

2
@ James, penso che dovrebbe essere min(abs(c(x%%1, x%%1-1))) < tolinvece che abs(min(x%%1, x%%1-1)) < tolaltrimenti, otterrai FALSEper qualsiasi numero intero ...
Cath

3
Cosa c'è che non va as.integer(x) == x? Non rifiuterà 3 o 3.0 come is.integer(x)farebbe e catturerà 3.1.
Gabi

34

Ecco una soluzione che utilizza funzioni più semplici e nessun hack:

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

Inoltre, puoi testare un intero vettore contemporaneamente, se lo desideri. Ecco una funzione:

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

Puoi cambiarlo per usarlo *applynel caso di vettori, matrici, ecc.


11
L'ultimo if elsepotrebbe essere fatto semplicemente isTRUE(test). In effetti questo è tutto ciò che serve per sostituire la if elseclausola e le returnistruzioni poiché R restituisce automaticamente il risultato dell'ultima valutazione.
Gavin Simpson

7
testInteger(1.0000001)[1] FALSO testInteger(1.00000001)[1] VERO
PatrickT

3
all(a == as.integer(a))aggira questo problema! '
Alex

Questo non funziona correttamente! Controlla il seguente controesempio: 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

Leggere la documentazione in linguaggio R as.integerha più a che fare con il modo in cui il numero viene memorizzato che se è praticamente equivalente a un numero intero. is.integerverifica se il numero è dichiarato come numero intero. Puoi dichiarare un numero intero inserendolo Ldopo.

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

Anche funzioni come roundrestituirà un intero dichiarato, che è ciò che stai facendo x==round(x). Il problema con questo approccio è ciò che consideri praticamente un numero intero. L'esempio utilizza una minore precisione per testare l'equivalenza.

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

Quindi, a seconda dell'applicazione, potresti finire nei guai in questo modo.


1
La seconda riga dice "as.integer verifica se il numero è dichiarato come intero". ma sono abbastanza sicuro che volevi dire "is.integer". È solo una modifica di un carattere quindi non potrei cambiarlo facilmente.
Peter Vermont

10

Eccone uno, apparentemente affidabile:

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

Questa soluzione consente anche di inserire numeri interi nella notazione scientifica:

> check.integer(222e3)
[1] TRUE

1
Questo non mi sembra molto affidabile: check.integer(1e4)è VERO, mentre check.integer(1e5)è FALSO.
WCH

5
-1 Questo è peggio di is.wholenumbero di una qualsiasi delle altre soluzioni fornite in altre risposte. Queste non dovrebbero essere diversi: check.integer(1e22); check.integer(1e23). Puoi ovviamente cambiare la regex per risolvere questo problema, ma questo approccio è terribile. (Il commento viene dall'attribuzione nel pacchetto installr.)
Joshua Ulrich

1
@PatrickT, capisco. È l'argomento della cifra predefinita. usa format(40, scientific = FALSE, digits = 20)invece. Ho aggiornato la risposta. Grazie per averlo notato.
VitoshKa

1
@PatrickT Sei nel regno degli errori di arrotondamento dipendenti dalla macchina. Sotto questo aspetto la mia soluzione è la stessa di quella accettata 1.0000000000000001 == 1L [1] TRUE. Ma la mia soluzione è migliore se ottieni già un numero sotto forma di stringacheck.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa

4
@VitoshKa ha adorato la tua risposta! Sebbene ci sia un punto che hai perso, anche i numeri negativi senza punti decimali sono interi;) Ho modificato il tuo codice di conseguenza.
Mehrad Mahmoudian

8

Sembra che tu non veda la necessità di incorporare una certa tolleranza agli errori. Non sarebbe necessario se tutti i numeri interi venissero inseriti come numeri interi, tuttavia a volte derivano da operazioni aritmetiche che perdono un po 'di precisione. Per esempio:

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

Nota che questa non è la debolezza di R, tutti i software per computer hanno alcuni limiti di precisione.


3
nel caso in cui alcune persone non capiscano cosa è successo qui ... se inserisci come.integer (2/49 * 49) ottieni 1 !! [BTW, è sempre così frustrante che R non presenti il ​​risultato del calcolo iniziale come 2.0 per rappresentare che il valore ha una componente decimale) vedi ... stackoverflow.com/questions/1535021/…
John

6

Da Hmisc::spss.get:

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

opzione molto più sicura, IMHO, poiché "aggira" il problema della precisione della macchina. Se ci provi is.integer(floor(1)), otterrai FALSE. A proposito, il tuo numero intero non verrà salvato come numero intero se è più grande del .Machine$integer.maxvalore, che è, per impostazione predefinita, 2147483647, quindi modifica il integer.maxvalore o esegui i controlli alternativi ...


1
se x <- sqrt(2)^2, poi all(floor(x) == x, na.rm = TRUE)ritornoFALSE
Corrado

3

puoi usare semplici condizioni if ​​come:

if(round(var) != var)­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

1

In R, se un numero è numerico o intero può essere determinato dalla funzione di classe. Generalmente tutti i numeri vengono memorizzati come numerici e per definire esplicitamente un numero come intero è necessario specificare "L" dopo il numero.

Esempio:

x <- 1

classe (x)

[1] "numerico"

x <- 1L

classe (x)

[1] "numero intero"

Spero che questo sia ciò di cui avevamo bisogno. Grazie :)


0

[AGGIORNAMENTO] =============================================== ===============

Rispetto alla [VECCHIA] risposta qui sotto, ho scoperto che funzionava perché ho messo tutti i numeri in un unico vettore atomico; uno di loro era un personaggio, quindi tutti diventano personaggi.

Se usiamo una lista (quindi, la coercizione non avviene) tutti i test passano correttamente tranne uno:, 1/(1 - 0.98)che rimane a numeric. Questo perché il tolparametro è di default 100 * .Machine$double.epse quel numero è tutt'altro che 50poco inferiore al doppio di quello. Quindi, in sostanza, per questo tipo di numeri, noi dobbiamo decidere la nostra tolleranza!

Quindi, se vuoi che tutti i test diventino TRUE, puoi farloassertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

Ad ogni modo, confermo che l'assertivo IMO rimane la soluzione migliore.

Di seguito un rappresentante per questo [AGGIORNAMENTO].

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

Creato il 23/07/2019 dal pacchetto reprex (v0.3.0)

[VECCHIO] =============================================== ==================

IMO la soluzione migliore viene dal assertivepacchetto (che, per il momento, risolve tutti gli esempi positivi e negativi in ​​questo thread):

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

Creato il 23/07/2019 dal pacchetto reprex (v0.3.0)



0

Once può anche usare dplyr::near:

library(dplyr)

near(a, as.integer(a))

Si applica a qualsiasi vettore ae ha un parametro di tolleranza opzionale.


-3

Non sono sicuro di cosa stai cercando di ottenere. Ma qui ci sono alcuni pensieri:
1. Converti in intero:
num = as.integer(123.2342)
2. Controlla se una variabile è un numero intero:
is.integer(num)
typeof(num)=="integer"


Mi sto solo assicurando che gli utenti inseriscano un numero appropriato - stiamo parlando del numero di "soggetti", che può essere solo un numero intero.
Roman Luštrik
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.