Periksa apakah angkanya adalah bilangan bulat

105

Saya terkejut mengetahui bahwa R tidak datang dengan fungsi praktis untuk memeriksa apakah angkanya adalah integer.

is.integer(66) # FALSE

File bantuan memperingatkan :

is.integer(x)tidak menguji apakah x berisi bilangan bulat! Untuk itu, gunakan round, seperti pada fungsi is.wholenumber(x)pada contoh.

Contoh memiliki fungsi kustom sebagai "solusi"

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

Jika saya harus menulis fungsi untuk memeriksa bilangan bulat, dengan asumsi saya belum membaca komentar di atas, saya akan menulis fungsi yang akan melakukan sesuatu di sepanjang baris

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

Dimana pendekatan saya akan gagal? Apa pekerjaan Anda jika Anda berada dalam posisi hipotetis saya?

Roman Luštrik
sumber
Saya berharap jika round(x)diimplementasikan dengan benar, hasil penerapannya ke integer akan selalu menjadi integer itu ...
Stephen
Lihatlah FAQ di R cran.r-project.org/doc/FAQ/…
Richie Cotton
5
> check.integer (9.0) [1] BENAR bukan.
Peng Peng
@PengPeng, VitoshKa memperbaiki ini dalam jawaban yang diterima.
Roman Luštrik
4
Saya rasa ada kebingungan tentang konsep matematika dan komputasi bilangan bulat. Fungsi is.integermemeriksa konsep komputasi, check.integerfungsi pengguna memeriksa sudut pandang matematika.
João Daniel

Jawaban:

126

Alternatif lain adalah memeriksa bagian pecahan:

x%%1==0

atau, jika Anda ingin memeriksa dalam toleransi tertentu:

min(abs(c(x%%1, x%%1-1))) < tol
James
sumber
1
apakah saran pemeriksaan toleransi benar-benar berfungsi ?? x <- 5-1e-8; x%%1memberikan 0.9999999 (yang akan berarti jika tol==1e-5misalnya) yang xmerupakan bukan integer.
Ben Bolker
@BenBolker Tangkapan bagus, ini bekerja untuk gangguan positif menurut saya. Saya telah mengubahnya menjadi solusi alternatif yang seharusnya berfungsi.
Yakobus
2
@ James, saya pikir seharusnya min(abs(c(x%%1, x%%1-1))) < tolalih - alih abs(min(x%%1, x%%1-1)) < tolsebaliknya, Anda akan mendapatkan FALSEbilangan bulat apa pun ...
Cath
3
Ada apa dengan as.integer(x) == x? Itu tidak akan menolak 3 atau 3.0 seperti yang is.integer(x)akan terjadi, dan itu akan menangkap 3.1.
Gabi
34

Berikut solusi menggunakan fungsi yang lebih sederhana dan tanpa peretasan:

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

Terlebih lagi, Anda dapat menguji seluruh vektor sekaligus, jika Anda mau. Inilah fungsinya:

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

Anda dapat mengubahnya untuk digunakan *applydalam kasus vektor, matriks, dll.

Iterator
sumber
11
Yang terakhir if elsebisa dilakukan dengan sederhana isTRUE(test). Memang hanya itu yang Anda butuhkan untuk mengganti if elseklausa dan returnpernyataan karena R secara otomatis mengembalikan hasil evaluasi terakhir.
Gavin Simpson
7
testInteger(1.0000001)[1] SALAH testInteger(1.00000001)[1] BENAR
PatrickT
3
all(a == as.integer(a))mengatasi masalah ini! '
Alex
Ini tidak berfungsi dengan benar! Lihat counter-example berikut: 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

Membaca dokumentasi bahasa R, as.integerlebih berkaitan dengan bagaimana nomor disimpan daripada jika secara praktis setara dengan bilangan bulat. is.integertes jika nomor tersebut dideklarasikan sebagai integer. Anda dapat mendeklarasikan integer dengan meletakkan a Lsetelahnya.

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

Juga fungsi seperti roundakan mengembalikan integer yang dideklarasikan, yang sedang Anda lakukan x==round(x). Masalah dengan pendekatan ini adalah apa yang Anda anggap praktis sebagai bilangan bulat. Contoh tersebut menggunakan presisi yang kurang untuk menguji kesetaraan.

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

Jadi tergantung pada aplikasi Anda, Anda bisa mendapat masalah dengan cara itu.

Andrew Redd
sumber
1
Baris kedua mengatakan "as.integer tes jika nomor tersebut dideklarasikan sebagai integer." tapi saya cukup yakin yang Anda maksud adalah "is.integer". Ini hanya satu edit karakter jadi saya tidak bisa dengan mudah mengubahnya.
PeterVermont
10

Inilah satu cara yang tampaknya dapat diandalkan:

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

Solusi ini juga memungkinkan bilangan bulat dalam notasi ilmiah:

> check.integer(222e3)
[1] TRUE
VitoshKa
sumber
1
Ini tampaknya tidak terlalu bisa diandalkan untuk saya: check.integer(1e4)BENAR, sedangkan check.integer(1e5)SALAH.
Minggu
5
-1 Ini lebih buruk dari is.wholenumber, atau solusi lain yang diberikan dalam jawaban lain. Ini seharusnya tidak berbeda: check.integer(1e22); check.integer(1e23). Anda jelas dapat mengubah regex untuk memperbaikinya, tetapi pendekatan ini mengerikan. (Komentar berasal dari atribusi dalam paket installr.)
Joshua Ulrich
1
@PatrickT, begitu. Ini argumen digit default. gunakan format(40, scientific = FALSE, digits = 20)sebagai gantinya. Saya telah memperbarui jawabannya. Terima kasih sudah melihatnya.
VitoshKa
1
@PatrickT Anda berada di ranah kesalahan pembulatan yang bergantung pada mesin. Dalam hal itu, solusi saya sama dengan solusi yang diterima 1.0000000000000001 == 1L [1] TRUE. Tetapi solusi saya lebih baik jika Anda sudah mendapatkan nomor dalam bentuk stringcheck.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa
4
@VitoshKa menyukai jawaban Anda! Meskipun ada satu poin yang Anda lewatkan, angka negatif tanpa titik desimal juga merupakan bilangan bulat;) Saya mengubah kode Anda.
Mehrad Mahmoudian
8

Tampaknya Anda tidak melihat kebutuhan untuk memasukkan beberapa toleransi kesalahan. Ini tidak akan diperlukan jika semua bilangan bulat dimasukkan sebagai bilangan bulat, namun kadang-kadang mereka datang sebagai hasil dari operasi aritmatika yang kehilangan beberapa presisi. Sebagai contoh:

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

Perhatikan bahwa ini bukan kelemahan R, semua perangkat lunak komputer memiliki beberapa batasan presisi.

Aniko
sumber
3
kalau-kalau beberapa orang tidak mengerti apa yang terjadi di sini ... jika Anda memasukkan as.integer (2/49 * 49) Anda mendapatkan 1 !! [BTW, sangat menyebalkan bahwa R tidak menampilkan hasil kalkulasi awal sebagai 2.0 untuk menyatakan bahwa nilai tersebut memiliki beberapa komponen desimal) lihat ... stackoverflow.com/questions/1535021/…
John
6

Dari Hmisc::spss.get:

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

pilihan yang jauh lebih aman, IMHO, karena "melewati" masalah presisi mesin. Jika Anda mencoba is.integer(floor(1)), Anda akan mendapatkan FALSE. BTW, bilangan bulat Anda tidak akan disimpan sebagai bilangan bulat jika lebih besar dari .Machine$integer.maxnilai, yaitu, secara default 2147483647, jadi ubah integer.maxnilainya, atau lakukan pemeriksaan alternatif ...

aL3xa
sumber
1
jika x <- sqrt(2)^2, kemudian all(floor(x) == x, na.rm = TRUE)kembaliFALSE
Corrado
3

Anda bisa menggunakan simple if condition seperti:

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

Di R, apakah suatu angka adalah numerik atau integer dapat ditentukan oleh fungsi kelas. Umumnya semua angka disimpan sebagai numerik dan untuk secara eksplisit mendefinisikan angka sebagai integer kita perlu menentukan 'L' setelah angka tersebut.

Contoh:

x <- 1

kelas (x)

[1] "numerik"

x <- 1L

kelas (x)

[1] "integer"

Saya harap inilah yang dibutuhkan. Terima kasih :)

Meenansha Sachdeva
sumber
0

[UPDATE] =============================================== ===============

Sehubungan dengan jawaban [LAMA] di sini di bawah, saya telah menemukan bahwa itu berhasil karena saya telah meletakkan semua angka dalam satu vektor atom; salah satunya adalah karakter, jadi setiap orang menjadi karakter.

Jika kita menggunakan daftar (karena itu, pemaksaan tidak terjadi) semua tes lulus dengan benar kecuali satu 1/(1 - 0.98):, yang tetap a numeric. Ini karena tolparameternya secara default 100 * .Machine$double.epsdan angka itu jauh dari 50kurang dari dua kali lipatnya. Jadi, pada dasarnya, untuk jenis angka ini, kita harus memutuskan toleransi kita!

Jadi jika Anda ingin semua tes menjadi TRUE, Anda bisaassertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

Bagaimanapun, saya menegaskan bahwa IMO tegas tetap merupakan solusi terbaik.

Berikut di bawah ini reprex untuk [PEMBARUAN] ini.

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

Dibuat pada 2019-07-23 oleh paket reprex (v0.3.0)

[LAMA] =============================================== ==================

IMO solusi terbaik berasal dari assertivepaket (yang, untuk saat ini, menyelesaikan semua contoh positif dan negatif di utas ini):

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

Dibuat pada 2019-07-23 oleh paket reprex (v0.3.0)

Corrado
sumber
0

Once juga bisa menggunakan dplyr::near:

library(dplyr)

near(a, as.integer(a))

Ini berlaku untuk vektor apa pun a, dan memiliki parameter toleransi opsional.

James Hirschorn
sumber
-3

Saya tidak yakin apa yang ingin Anda capai. Tapi di sini ada beberapa pemikiran:
1. Convert to integer:
num = as.integer(123.2342)
2. Periksa apakah suatu variabel adalah integer:
is.integer(num)
typeof(num)=="integer"

Bernardw
sumber
Saya hanya memastikan pengguna memasukkan nomor yang sesuai - kita berbicara tentang jumlah "subjek", yang hanya bisa berupa bilangan bulat.
Roman Luštrik