【问题标题】:Check if the number is integer检查数字是否为整数
【发布时间】:2010-08-13 12:30:39
【问题描述】:

我很惊讶地发现 R 没有一个方便的函数来检查数字是否为整数。

is.integer(66) # FALSE

help files warns

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

如果我必须写一个函数来检查整数,假设我没有读过上面的 cmets,我会写一个函数来做一些事情

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

我的方法会在哪里失败?如果你在我假设的鞋子里,你会怎么做?

【问题讨论】:

  • 我希望如果round(x)被正确实现,将其应用于整数的结果将始终是该整数...
  • 查看 R cran.r-project.org/doc/FAQ/… 上的常见问题解答
  • > check.integer(9.0) [1] 不是的。
  • @PengPeng,VitoshKa 在接受的答案中解决了这个问题。
  • 我认为整数的数学和计算概念存在混淆。 is.integer 函数检查计算概念,check.integer 用户函数检查数学观点。

标签: r integer rounding


【解决方案1】:

另一种方法是检查小数部分:

x%%1==0

或者,如果您想在某个公差范围内进行检查:

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

【讨论】:

  • 公差检查建议真的有效吗? x &lt;- 5-1e-8; x%%1 给出 0.9999999(例如,如果 tol==1e-5 意味着)x 不是一个整数。
  • @BenBolker 很好,我认为它适用于积极的扰动。我已将其更改为替代解决方案应该可以工作。
  • @James,我认为应该是 min(abs(c(x%%1, x%%1-1))) &lt; tol 而不是 abs(min(x%%1, x%%1-1)) &lt; tol 否则,任何整数都会得到 FALSE...
  • as.integer(x) == x 有什么问题?它不会像is.integer(x) 那样拒绝 3 或 3.0,它会捕获 3.1。
【解决方案2】:

这是一个使用更简单的功能且没有 hack 的解决方案:

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

【讨论】:

  • 最后一个if else 可以简单地用isTRUE(test) 完成。事实上,这就是您替换 if else 子句和 return 语句所需的全部内容,因为 R 会自动返回最后一次评估的结果。
  • testInteger(1.0000001) [1] 错误 testInteger(1.00000001) [1] 正确
  • all(a == as.integer(a)) 解决了这个问题!'
  • 这不能正常工作!查看以下反例:frac_test
【解决方案3】:

这是一种显然可靠的方法:

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

【讨论】:

  • 这对我来说看起来不太可靠:check.integer(1e4) 是 TRUE,而 check.integer(1e5) 是 FALSE。
  • -1 这比is.wholenumber 或其他答案中提供的任何其他解决方案更糟糕。这些不应该有所不同:check.integer(1e22); check.integer(1e23)。您显然可以更改正则表达式来解决此问题,但这种方法很糟糕。 (评论来自安装包中的归属。)
  • @PatrickT,我明白了。这是默认数字的参数。请改用format(40, scientific = FALSE, digits = 20)。我已经更新了答案。感谢您发现它。
  • @PatrickT 您处于机器相关舍入错误的领域。在这方面,我的解决方案与接受的1.0000000000000001 == 1L [1] TRUE 相同。但是如果你已经得到一个字符串形式的数字check.integer("1000000000000000000000000000000000001") [1] TRUE,我的解决方案会更好
  • @VitoshKa 喜欢你的回答!尽管您遗漏了一点,但没有小数点的负数也是整数;)我相应地修改了您的代码。
【解决方案4】:

阅读 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

因此,根据您的应用程序,您可能会以这种方式遇到麻烦。

【讨论】:

  • 第二行说“as.integer 测试数字是否被声明为整数。”但我很确定你的意思是“is.integer”。这只是一个字符的编辑,所以我不能轻易改变它。
【解决方案5】:

您似乎认为没有必要加入一些容错性。如果所有整数都作为整数输入,则不需要它,但是有时它们是由于算术运算失去了一些精度而出现的。例如:

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

请注意,这不是 R 的弱点,所有计算机软件都有一些精度限制。

【讨论】:

  • 以防万一有些人不太明白这里发生了什么......如果你输入 as.integer(2/49*49) 你会得到 1 ! [顺便说一句,令人沮丧的是,R 没有将初始计算的结果显示为 2.0 以表示该值具有一些小数部分)请参阅...stackoverflow.com/questions/1535021/…
【解决方案6】:

来自Hmisc::spss.get

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

更安全的选择,恕我直言,因为它“绕过”了机器精度问题。如果你尝试is.integer(floor(1)),你会得到FALSE。顺便说一句,如果您的整数大于 .Machine$integer.max 值(默认为 2147483647),则不会将其保存为整数,因此要么更改 integer.max 值,要么进行其他检查...

【讨论】:

  • 如果x &lt;- sqrt(2)^2,则all(floor(x) == x, na.rm = TRUE)返回FALSE
【解决方案7】:

您可以使用简单的 if 条件,例如:

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

【讨论】:

    【解决方案8】:

    在R中,数字是数字还是整数可以通过类函数来确定。通常,所有数字都存储为数字,要明确将数字定义为整数,我们需要在数字后指定“L”。

    例子:

    x

    类(x)

    [1]“数字”

    x

    类(x)

    [1]“整数”

    我希望这是我们所需要的。谢谢:)

    【讨论】:

      【解决方案9】:

      [更新] ============================================= ===================

      尊重下面的 [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] 的代表。

      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 package (v0.3.0) 于 2019 年 7 月 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 package (v0.3.0) 于 2019 年 7 月 23 日创建

      【讨论】:

        【解决方案10】:

        如果您不想编写自己的函数,请尝试 installr 包中的 check.integer。目前it usesVitoshKa 的回答。

        也可以试试 varhandle 包中的 check.numeric(v, only.integer=TRUE),它具有矢量化的好处。

        【讨论】:

          【解决方案11】:

          一次也可以使用dplyr::near

          library(dplyr)
          
          near(a, as.integer(a))
          

          它适用于任何向量a,并且有一个可选的公差参数。

          【讨论】:

            【解决方案12】:

            对于向量mm[round(m) != m] 将返回向量中非整数值的索引。

            【讨论】:

              【解决方案13】:

              我不确定您要完成什么。但这里有一些想法:
              1.转换为整数:
              num = as.integer(123.2342)
              2. 检查变量是否为整数:
              is.integer(num)
              typeof(num)=="integer"

              【讨论】:

              • 我只是确保用户输入了一个合适的数字——我们说的是“主题”的数量,它只能是一个整数。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-08-13
              • 2023-03-18
              • 2016-02-18
              • 2011-07-27
              相关资源
              最近更新 更多