Перевірте, чи число ціле


106

Я здивувався, дізнавшись, що R не має зручної функції перевірити, чи є ціле число.

is.integer(66) # FALSE

Ці файли довідки попереджає :

is.integer(x)не перевіряє, чи x містить цілі числа! Для цього використовуйте round, як у функції is.wholenumber(x)в прикладах.

У прикладі є ця спеціальна функція як "вирішення"

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

Якщо мені доведеться написати функцію для перевірки цілих чисел, припускаючи, що я не читав вищезазначених коментарів, я б написав функцію, яка б щось ішла по лінії

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

Де мій підхід не вдасться? Якою була б робота над вами, якби ви були в моїх гіпотетичних черевиках?


Я би сподівався, що якщо round(x)правильно його реалізувати, результатом його застосування до цілого числа завжди буде це ціле число ...
Stephen

Подивіться на FAQ на R cran.r-project.org/doc/FAQ/…
Річі Коттон,

5
> check.integer (9.0) [1] ІСТИНА це не так.
Пен Пенг

@PengPeng, VitoshKa зафіксував це у прийнятій відповіді.
Роман Луштрик

4
Я думаю, що виникає плутанина щодо математичних та обчислювальних понять цілого числа. Функція is.integerперевіряє обчислювальну концепцію, check.integerфункція користувача перевіряє математичну точку зору.
Жоано Даніель

Відповіді:


126

Ще одна альтернатива - перевірити дробову частину:

x%%1==0

або, якщо ви хочете перевірити певний допуск:

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

1
чи дійсно пропозиція перевірки толерантності дійсно працює ?? x <- 5-1e-8; x%%1дає 0.9999999 (що означало б , якщо tol==1e-5, наприклад) , що xце НЕ є цілим числом.
Бен Болкер

@BenBolker Хороший улов, я думаю, що це працює для позитивних збурень. Я змінив його на альтернативне рішення повинно працювати.
Джеймс

2
@James, я думаю, що це має бути min(abs(c(x%%1, x%%1-1))) < tolзамість abs(min(x%%1, x%%1-1)) < tolіншого, ви отримаєте FALSEза будь-яке ціле число ...
Cath

3
Що не так as.integer(x) == x? Він не відхилить 3 або 3.0, як is.integer(x)хотілося б, і отримає 3.1.
Габі

34

Ось рішення з використанням більш простих функцій і без хак:

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

Більше того, ви можете протестувати цілий вектор одразу, якщо хочете. Ось функція:

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

Ви можете змінити його на використання *applyу випадку векторів, матриць тощо.


11
Останнє if elseможна зробити просто isTRUE(test). Дійсно, це все, що потрібно для заміни if elseпункту та returnтверджень, оскільки R автоматично повертає результат останньої оцінки.
Гевін Сімпсон

7
testInteger(1.0000001)[1] FALSE testInteger(1.00000001)[1] ІСТИНА
PatrickT

3
all(a == as.integer(a))долає цю проблему! '
Алекс

Це не працює належним чином! Перевірте такий зустрічний приклад: 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 as.integerмає більше спільного з тим, як зберігається число, ніж якщо воно практично еквівалентне цілому. is.integerтести, якщо число оголошено цілим числом. Можна оголосити ціле число, поставивши Lпісля нього.

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

Також такі функції, як roundповертають оголошене ціле число, для чого ви робите x==round(x). Проблема такого підходу - це те, що ви вважаєте практично цілим числом. У прикладі використовується менша точність для перевірки еквівалентності.

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

Отже, залежно від вашої заявки, ви можете таким чином потрапити в проблеми.


1
У другому рядку написано "as.integer тестує, якщо число оголошено цілим числом". але я впевнений, що ти мав на увазі "is.integer". Це лише одна символьна редакція, тому я не міг її легко змінити.
PeterVermont

10

Ось один, мабуть, надійний спосіб:

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

Це рішення також дозволяє вводити цілі числа в наукові позначення:

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

1
Це не дуже надійно для мене: check.integer(1e4)це ІСТИНА, а check.integer(1e5)ЛЖА.
wch

5
-1 Це гірше, ніж is.wholenumberбудь-яке інше рішення, передбачене в інших відповідях. Вони не повинні бути різними: check.integer(1e22); check.integer(1e23). Ви, очевидно, можете змінити регулярний вираз, щоб виправити це, але такий підхід є жахливим. (Коментар походить від атрибуції в інсталярському пакеті.)
Джошуа Ульріх

1
@PatrickT, я бачу. Це аргумент цифри за замовчуванням. використовувати format(40, scientific = FALSE, digits = 20)замість цього. Я оновив відповідь. Дякуємо, що помітили його.
VitoshKa

1
@PatrickT Ви знаходитесь у царині машинозалежних помилок округлення. У цьому відношенні моє рішення те саме, що прийняте 1.0000000000000001 == 1L [1] TRUE. Але моє рішення краще, якщо ви вже отримаєте номер у check.integer("1000000000000000000000000000000000001") [1] TRUE
рядковій

4
@VitoshKa сподобався вашій відповіді! Хоча є один момент, який ви пропустили, негативні числа без десяткових знаків також є цілими;) Я відповідно змінив ваш код.
Мехрад Махмудян

8

Виявляється, ви не бачите необхідності включати деяку толерантність до помилок. Це було б не потрібно, якби всі цілі числа входили як цілі числа, проте іноді вони виникають у результаті арифметичних операцій, які втрачають певну точність. Наприклад:

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

Зауважте, що це не слабкість R, все програмне забезпечення комп'ютера має деякі межі точності.


3
про всяк випадок, якщо хтось не зовсім зрозумів, що сталося тут ... якщо ви введете as.integer (2/49 * 49), ви отримаєте 1 !! [BTW, це настільки засмучує, що R не представляє результату початкового обчислення як 2.0, щоб представити, що значення має деяку десяткову складову) див. ... stackoverflow.com/questions/1535021/…
Джон

6

Від Hmisc::spss.get:

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

набагато безпечніший варіант, IMHO, оскільки він "обходить" проблему точності машини. Якщо ви спробуєте is.integer(floor(1)), ви отримаєте FALSE. BTW, ваше ціле число не буде збережене як ціле, якщо воно більше .Machine$integer.maxзначення, яке за замовчуванням 2147483647, тому або змініть integer.maxзначення, або зробіть альтернативні перевірки ...


1
якщо x <- sqrt(2)^2, тоді all(floor(x) == x, na.rm = TRUE)повертайтесяFALSE
Коррадо

3

Ви можете використовувати прості, якщо такі умови:

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

1

У R чи число чисельне чи ціле число можна визначити функцією класу. Як правило, всі числа зберігаються як числові, і щоб чітко визначити число як ціле, нам потрібно вказати "L" після числа.

Приклад:

х <- 1

клас (х)

[1] "числовий"

х <- 1л

клас (х)

[1] "ціле число"

Я сподіваюсь, що це було потрібно. Дякую :)


0

[ОНОВЛЕННЯ] ================================================== ===============

Поважаючи відповідь [СТАРИЙ] тут нижче, я виявив, що він працює, тому що я поставив усі числа в один атомний вектор; один з них був персонажем, тому кожен стає персонажем.

Якщо ми використовуємо список (отже, примус не відбувається), всі тести проходять правильно, але один:, 1/(1 - 0.98)який залишається а numeric. Це тому, що tolпараметр за замовчуванням, 100 * .Machine$double.epsі це число далеко 50не менше, ніж удвічі. Тож, в основному, для таких чисел ми маємо вирішити нашу толерантність!

Тож якщо ви хочете, щоб усі випробування стали TRUE , ви можетеassertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

У всякому разі, я підтверджую, що твердження ІМО залишається найкращим рішенням.

Тут нижче репрексу для цього [ОНОВЛЕННЯ].

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

Створено 2019-07-23 пакетом reprex (v0.3.0)

[OLD] ================================================== ===================

Найкраще рішення IMO виходить із assertiveпакету (який на даний момент вирішує всі позитивні та негативні приклади в цій темі):

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

Створено 2019-07-23 пакетом reprex (v0.3.0)



0

Після цього також можна використовувати dplyr::near:

library(dplyr)

near(a, as.integer(a))

Він застосовується до будь-якого вектора aі має необов'язковий параметр допуску.


-3

Я не впевнений, що ви намагаєтеся досягти. Але ось кілька думок:
1. Перетворити на ціле число:
num = as.integer(123.2342)
2. Перевірити, чи є змінною ціле число:
is.integer(num)
typeof(num)=="integer"


Я просто переконуюсь, що користувачі вводять відповідне число - ми говоримо про кількість "предметів", яка може бути лише цілим числом.
Роман Луштрик
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.