숫자가 정수인지 확인


104

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


5
> check.integer (9.0) [1] TRUE 그렇지 않습니다.
Peng Peng

@PengPeng, VitoshKa는 수락 된 답변에서 이것을 수정했습니다.
Roman Luštrik

4
정수의 수학적 및 계산적 개념에 대해 혼란이 있다고 생각합니다. 이 함수 is.integer는 계산 개념을 확인하고 check.integer사용자 함수는 수학적 관점을 확인합니다.
João Daniel

답변:


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
Ben Bolker 2014 년

@BenBolker 좋은 캐치, 내 생각에 긍정적 인 섭동에 대해 작동합니다. 대체 솔루션으로 변경했습니다.
James

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을 잡을 것입니다.
Gabi

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). 실제로 R은 마지막 평가의 결과를 자동으로 반환하므로 if else절과 return문 을 교체하는 데 필요한 전부 입니다.
Gavin Simpson

7
testInteger(1.0000001)[1] FALSE testInteger(1.00000001)[1] TRUE
PatrickT 2015 년

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뒤에 a를 넣어 정수를 선언 할 수 있습니다 .

> 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). 이 문제를 해결하기 위해 정규식을 분명히 변경할 수 있지만이 방법은 끔찍합니다. (코멘트는 installr 패키지의 속성에서 비롯됩니다.)
여호수아 울리히

1
@PatrickT, 알겠습니다. 기본 숫자의 인수입니다. 사용하는 format(40, scientific = FALSE, digits = 20)대신. 답변을 업데이트했습니다. 찾아 주셔서 감사합니다.
VitoshKa

1
@PatrickT 당신은 기계 의존 반올림 오류의 영역에 있습니다. 그 점에서 내 솔루션은 허용 된 솔루션과 동일합니다 1.0000000000000001 == 1L [1] TRUE. 하지만 내 솔루션은 이미 문자열 형식에 숫자를 얻는 경우에 더 낫다check.integer("1000000000000000000000000000000000001") [1] TRUE
VitoshKa

4
@VitoshKa는 귀하의 답변을 좋아했습니다! 놓친 점이 하나 있지만 소수점이없는 음수도 정수입니다.) 그에 따라 코드를 수정했습니다.
Mehrad Mahmoudian 2015

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/…
John

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 조건을 사용할 수 있습니다.

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

1

R에서 숫자가 숫자인지 정수인지는 클래스 함수에 의해 결정될 수 있습니다. 일반적으로 모든 숫자는 숫자로 저장되며 숫자를 정수로 명시 적으로 정의하려면 숫자 뒤에 'L'을 지정해야합니다.

예:

x <-1

클래스 (x)

[1] "숫자"

x <-1L

클래스 (x)

[1] "정수"

이것이 필요한 것이기를 바랍니다. 감사 :)


0

[업데이트] ============================================== ===============

아래의 [OLD] 답변에 대해 저는 모든 숫자를 단일 원자 벡터에 넣었 기 때문에 작동한다는 것을 발견했습니다. 그들 중 하나는 캐릭터 였으므로 모두가 캐릭터가됩니다.

목록을 사용하면 (따라서 강제가 발생하지 않음) 모든 테스트가 올바르게 통과되지만 하나 1/(1 - 0.98)numeric. 이것은 tol매개 변수가 기본 100 * .Machine$double.eps이고 그 숫자는 50그 두 배보다 조금 작기 때문입니다. 그래서 기본적으로 이런 종류의 숫자에 대해 우리 우리의 관용을 결정해야합니다!

그래서 모든 테스트를 원한다면 TRUE 되었으면assertive::is_whole_number(x, tol = 200 * .Machine$double.eps)

어쨌든, 나는 IMO 주장이 최선의 해결 책임을 확인합니다.

여기에이 [UPDATE]에 대한 reprex가 있습니다.

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 패키지 (v0.3.0)에 의해 2019-07-23에 생성됨

[이전] ============================================= ==================

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

reprex 패키지 (v0.3.0)에 의해 2019-07-23에 생성됨



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"


저는 사용자가 적절한 숫자를 입력했는지 확인하는 것입니다. 우리는 정수일 수있는 "주체"의 수에 대해 이야기하고 있습니다.
Roman Luštrik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.