77

是的,我知道如果我们正好处于两个数字的中间(即 2.5 变为 2),为什么我们总是四舍五入到最接近的偶数。但是当我想为某些人评估数据时,他们不想要这种行为。得到这个的最简单的方法是什么:

x <- seq(0.5,9.5,by=1)
round(x)

为 1,2,3,...,10 而不是 0,2,2,4,4,...,10。

编辑:清除:四舍五入后 1.4999 应为 1。(我认为这很明显)

4

7 回答 7

86

这不是我自己的功能,不幸的是,我目前无法找到它的位置(最初在Statistically Significant博客上作为匿名评论找到),但它应该有助于满足您的需求。

round2 = function(x, n) {
  posneg = sign(x)
  z = abs(x)*10^n
  z = z + 0.5 + sqrt(.Machine$double.eps)
  z = trunc(z)
  z = z/10^n
  z*posneg
}

x是您要四舍五入的对象,n是您要四舍五入的位数。

一个例子

x = c(1.85, 1.54, 1.65, 1.85, 1.84)
round(x, 1)
# [1] 1.8 1.5 1.6 1.8 1.8
round2(x, 1)
# [1] 1.9 1.5 1.7 1.9 1.8

(感谢@Gregor 添加+ sqrt(.Machine$double.eps)。)

于 2012-10-02T10:43:13.367 回答
43

如果你想要round除了那些 xxx.5 值之外的行为完全一样的东西,试试这个:

x <- seq(0, 1, 0.1)
x
# [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
floor(0.5 + x)
# [1] 0 0 0 0 0 1 1 1 1 1 1
于 2012-10-02T10:55:44.813 回答
15

正如@CarlWitthoft 在评论中所说,这是IEC 60559 标准,如下所述?round

请注意,对于 5 的四舍五入,预计将使用 IEC 60559 标准,“转到偶数位”。因此,round(0.5) 为 0,而 round(-1.5) 为 -2。但是,这取决于操作系统服务和表示错误(因为例如 0.15 没有准确表示,舍入规则适用于表示的数字而不适用于打印的数字,因此 round(0.15, 1) 可以是 0.1 或 0.2 )。

Greg Snow的补充说明

取整规则背后的逻辑是,我们试图表示一个潜在的连续值,如果 x 来自一个真正的连续分布,那么 x==2.5 的概率为 0,并且 2.5 可能已经从任何值四舍五入一次在 2.45 和 2.54999999999999 之间...,如果我们使用我们在小学时学到的 0.5 规则向上舍入,那么双舍入意味着 2.45 和 2.50 之间的值将四舍五入为 3(首先四舍五入为 2.5)。这将倾向于向上偏差估计。为了消除偏差,我们需要回到四舍五入到 2.5 之前(这通常是不切实际的),或者只是将一半时间四舍五入并向下舍入一半时间(或者更好的是与我们的可能性成比例地四舍五入)将看到低于或高于 2.5 的值四舍五入为 2.5,但对于大多数基础分布而言,这将接近 50/50)。随机方法是让 round 函数随机选择哪种方式进行舍入,但确定性类型对此并不满意,因此选择“舍入到偶数”(舍入到奇数应该大致相同)作为舍入的一致规则上下约 50/50。

如果您正在处理 2.5 可能代表一个精确值(例如金钱)的数据,那么您可以通过将所有值乘以 10 或 100 并以整数工作,然后仅在最终打印时转换回来来做得更好。请注意,2.50000001 四舍五入为 3,因此如果您在最终打印之前保持更多位数的准确性,则四舍五入将按预期方向进行,或者您可以在四舍五入之前将 0.000000001(或其他小数字)添加到您的值,但这可以使您的估计向上偏斜。

于 2016-10-07T08:52:42.597 回答
9

这似乎有效:

rnd <- function(x) trunc(x+sign(x)*0.5)

Ananda Mahto 的回应似乎做到了这一点,甚至更多——我不确定他回应中的额外代码是什么原因;或者,换句话说,我不知道如何破坏上面定义的 rnd() 函数。

例子:

seq(-2, 2, by=0.5)
#  [1] -2.0 -1.5 -1.0 -0.5  0.0  0.5  1.0  1.5  2.0
round(x)
#  [1] -2 -2 -1  0  0  0  1  2  2
rnd(x)
#  [1] -2 -2 -1 -1  0  1  1  2  2
于 2013-09-23T18:02:19.700 回答
6

根据您对数据抖动的舒适程度,此方法有效:

round(x+10*.Machine$double.eps)
# [1]  1  2  3  4  5  6  7  8  9 10
于 2016-12-29T20:22:58.240 回答
3

这种方法:

round2 = function(x, n) {
  posneg = sign(x)
  z = abs(x)*10^n
  z = z + 0.5
  z = trunc(z)
  z = z/10^n
  z*posneg
}

当我们有很多位数的数字时,它似乎不能很好地工作。例如,doinground2(2436.845, 2)会给我们 2436.84。该问题似乎与该trunc(z)功能有关。

总的来说,我认为这与 R 存储数字的方式有关,因此truncandfloat函数并不总是有效。我能够以不是最优雅的方式绕过它:

round2 = function(x, n) {
  posneg = sign(x)
  z = abs(x)*10^n
  z = z + 0.5
  z = trunc(as.numeric(as.character(z)))
  z = z/10^n
  (z)*posneg
}
于 2020-06-24T02:16:05.480 回答
1

这模仿了在 0.5 处从零四舍五入:

round_2 <- function(x, digits = 0) {
  x = x + abs(x) * sign(x) * .Machine$double.eps
  round(x, digits = digits)
}

round_2(.5 + -2:4)
-2 -1  1  2  3  4  5
于 2020-01-27T14:26:04.007 回答