Sayının tam sayı olup olmadığını kontrol edin


107

R'nin sayının tamsayı olup olmadığını kontrol etmek için kullanışlı bir fonksiyona sahip olmadığını öğrendiğimde şaşırdım.

is.integer(66) # FALSE

Yardım dosyaları uyarıyor :

is.integer(x)x tamsayılar içerip içermediğini test etmez ! Bunun için örneklerdeki roundfonksiyonda olduğu gibi kullanın is.wholenumber(x).

Örnek, bu özel işlevi bir "geçici çözüm" olarak sunar

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

Tam sayıları kontrol etmek için bir fonksiyon yazmam gerekse, yukarıdaki yorumları okumadığımı varsayarak, satırları boyunca bir şeyler gidecek bir fonksiyon yazardım.

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

Yaklaşımım nerede başarısız olur? Varsayımsal ayakkabılarımın içinde olsaydın işin ne olurdu?


round(x)Düzgün bir şekilde uygulanırsa, onu bir tam sayıya uygulamanın sonucunun her zaman bu tam sayı olacağını umuyorum ...
Stephen


5
> check.integer (9.0) [1] DOĞRU değil.
Peng Peng

@PengPeng, VitoshKa bunu kabul edilen cevapta düzeltti.
Roman Luštrik

4
Bence matematiksel ve hesaplamalı tamsayı kavramları hakkında bir kafa karışıklığı var. Fonksiyon is.integerhesaplama konseptini kontrol eder, check.integerkullanıcı fonksiyonu matematiksel bakış açısını kontrol eder.
João Daniel

Yanıtlar:


127

Diğer bir alternatif ise kesirli kısmı kontrol etmektir:

x%%1==0

veya belirli bir tolerans dahilinde kontrol etmek istiyorsanız:

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

1
tolerans kontrolü önerisi gerçekten işe yarıyor mu? x <- 5-1e-8; x%%1verir 0.9999999 (eğer anlamına hangi tol==1e-5örneğin) o xolduğu olmayan bir tamsayıdır.
Ben Bolker

@BenBolker İyi yakaladım, bence olumlu tedirginlikler için çalışıyor. Çalışması gereken alternatif bir çözüme değiştirdim.
James

2
@James, ben olması gerektiğini düşünüyorum min(abs(c(x%%1, x%%1-1))) < tolyerine abs(min(x%%1, x%%1-1)) < tolalacağınız, aksi FALSE... tam sayılar için
Cath

3
Neyin var as.integer(x) == x? 3 veya 3.0 gibi reddetmeyecek is.integer(x)ve 3.1 yakalayacaktır.
Gabi

34

İşte daha basit işlevler kullanan ve hack içermeyen bir çözüm:

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

Dahası, dilerseniz bir seferde bütün bir vektörü test edebilirsiniz. İşte bir işlev:

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

*applyVektörler, matrisler vb. Durumlarda kullanmak üzere değiştirebilirsiniz .


11
Sonuncusu if elsebasitçe yapılabilir isTRUE(test). Gerçekten de, if elsecümle ve returnifadeleri değiştirmek için ihtiyacınız olan tek şey bu, çünkü R otomatik olarak son değerlendirmenin sonucunu döndürüyor.
Gavin Simpson

7
testInteger(1.0000001)[1] YANLIŞ testInteger(1.00000001)[1] DOĞRU
PatrickT

3
all(a == as.integer(a))bu sorunu çözüyor! '
Alex

Bu düzgün çalışmıyor! Aşağıdaki karşı örneği kontrol edin: 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

R dili belgelerini okumak as.integer, pratik olarak bir tamsayıya eşdeğer olduğundan daha çok sayının nasıl saklandığıyla ilgilidir. is.integersayının bir tamsayı olarak bildirilip bildirilmediğini test eder. Arkasına bir tamsayı koyarak bildirebilirsiniz L.

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

Ayrıca gibi işlevler round, yaptığınız şey olan, bildirilmiş bir tamsayı döndürür x==round(x). Bu yaklaşımla ilgili sorun, pratikte bir tam sayı olduğunu düşündüğünüz şeydir. Örnek, eşdeğerliği test etmek için daha az kesinlik kullanır.

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

Yani başvurunuza bağlı olarak bu şekilde başınız belaya girebilir.


1
İkinci satır "as. tamsayı, sayının bir tamsayı olarak bildirilip bildirilmediğini test eder" diyor. ama "is.integer" demek istediğinizden oldukça eminim. Bu sadece bir karakter düzenlemesi olduğundan kolayca değiştiremedim.
PeterVermont

10

Görünüşe göre güvenilir bir yol:

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

Bu çözüm ayrıca bilimsel gösterimde tam sayılara izin verir:

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

1
Bu bana pek güvenilir görünmüyor: check.integer(1e4)DOĞRU, check.integer(1e5)YANLIŞ.
wch

5
-1 Bu, is.wholenumberdiğer yanıtlarda sağlanan diğer çözümlerden veya herhangi birinden daha kötüdür . Bu farklı olmamalı: check.integer(1e22); check.integer(1e23). Bunu düzeltmek için normal ifadeyi açıkça değiştirebilirsiniz, ancak bu yaklaşım korkunçtur. (Yorum, installr paketindeki atıftan gelir.)
Joshua Ulrich

1
@PatrickT, görüyorum. Varsayılan rakamın argümanıdır. kullanmak format(40, scientific = FALSE, digits = 20)yerine. Cevabı güncelledim. Fark ettiğin için teşekkürler.
VitoshKa

1
@PatrickT Makineye bağlı yuvarlama hataları alemindesiniz. Bu bakımdan benim çözümüm, kabul edilen ile aynı 1.0000000000000001 == 1L [1] TRUE. Ama zaten dize biçiminde bir sayı alırsanız benim çözümüm daha iyicheck.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa

4
@VitoshKa cevabınızı beğendi! Kaçırdığınız bir nokta olmasına rağmen, ondalık noktası olmayan negatif sayılar da tam sayıdır;) Kodunuzu buna göre değiştirdim.
Mehrad Mahmoudian

8

Görünüşe göre bir miktar hata toleransı dahil etme gereğini görmüyorsunuz. Tüm tam sayıların tamsayı olarak girilmesi gerekli değildir, ancak bazen bir miktar hassasiyeti kaybeden aritmetik işlemlerin bir sonucu olarak gelirler. Örneğin:

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

Bunun R'nin zayıflığı olmadığını, tüm bilgisayar yazılımlarının bazı kesinlik sınırları olduğunu unutmayın.


3
sadece bazı insanlar burada olanları tam olarak anlamazsa ... tam sayı (2/49 * 49) olarak girerseniz 1 alırsınız !! [BTW, R'nin değerin bir miktar ondalık bileşeni olduğunu göstermek için ilk hesaplamanın sonucunu 2.0 olarak sunmaması her zamankinden çok sinir bozucu) bkz. Stackoverflow.com/questions/1535021/…
John

6

Kimden Hmisc::spss.get:

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

IMHO, makine hassasiyeti sorununu "atladığı" için çok daha güvenli bir seçenek. Eğer denersen is.integer(floor(1)), alacaksın FALSE. BTW, tamsayınız .Machine$integer.maxdeğerden büyükse tamsayı olarak kaydedilmeyecektir , bu varsayılan olarak 2147483647'dir, bu nedenle ya integer.maxdeğeri değiştirin ya da alternatif kontroller yapın ...


1
eğer x <- sqrt(2)^2, sonra all(floor(x) == x, na.rm = TRUE)geri dönFALSE
Corrado

3

basit if koşulu kullanabilirsiniz:

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

1

R'de, bir sayının sayısal mı yoksa tamsayı mı olduğu, sınıf işlevi tarafından belirlenebilir. Genel olarak tüm sayılar sayısal olarak saklanır ve bir sayıyı tamsayı olarak açıkça tanımlamak için, sayıdan sonra 'L' belirtmemiz gerekir.

Misal:

x <- 1

sınıf (x)

[1] "sayısal"

x <- 1L

sınıf (x)

[1] "tam sayı"

Umarım ihtiyaç duyulan buydu. Teşekkürler :)


0

[GÜNCELLEME] ============================================= ===============

Aşağıdaki [ESKİ] cevabına saygı duyarsak, bunun işe yaradığını keşfettim çünkü tüm sayıları tek bir atom vektörüne koydum; bunlardan biri bir karakterdi, bu yüzden her biri karakter oluyor.

Bir liste kullanırsak (dolayısıyla, zorlama olmaz), tüm testler doğru bir şekilde geçer 1/(1 - 0.98), ancak biri a kalır numeric. Bunun nedeni, tolparametrenin varsayılan olarak olması 100 * .Machine$double.epsve bu sayının 50bunun iki katından biraz daha az olmamasıdır. Yani öncelikle sayılar bu tür, biz var bizim hoşgörüyü karar vermek!

Yani tüm testlerin olmasını istiyorsanız TRUE, şunları yapabilirsiniz:assertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

Her neyse, IMO iddiasının en iyi çözüm olduğunu onaylıyorum.

Bu [GÜNCELLEME] için bir reprex aşağıda.

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

Reprex paketi (v0.3.0) tarafından 2019-07-23 tarihinde oluşturuldu

[ESKİ] ============================================= ==================

IMO en iyi çözüm assertivepaketten gelir (şu anda bu başlıktaki tüm olumlu ve olumsuz örnekleri çözen):

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

Reprex paketi (v0.3.0) tarafından 2019-07-23 tarihinde oluşturuldu



0

Bir kez ayrıca şunları da kullanabilir dplyr::near:

library(dplyr)

near(a, as.integer(a))

Herhangi bir vektör için geçerlidir ave isteğe bağlı bir tolerans parametresine sahiptir.


-3

Neyi başarmaya çalıştığından emin değilim. Ancak bazı düşünceler şunlardır:
1. Tamsayıya çevirin:
num = as.integer(123.2342)
2. Bir değişkenin tam sayı olup olmadığını kontrol edin:
is.integer(num)
typeof(num)=="integer"


Sadece kullanıcıların uygun bir sayı girdiğinden emin oluyorum - sadece bir tam sayı olabilen "özneler" sayısından bahsediyoruz.
Roman Luštrik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.