是的,我知道如果我们正好处于两个数字的中间(即 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。(我认为这很明显)
这不是我自己的功能,不幸的是,我目前无法找到它的位置(最初在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)
。)
如果你想要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
正如@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(或其他小数字)添加到您的值,但这可以使您的估计向上偏斜。
这似乎有效:
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
根据您对数据抖动的舒适程度,此方法有效:
round(x+10*.Machine$double.eps)
# [1] 1 2 3 4 5 6 7 8 9 10
这种方法:
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 存储数字的方式有关,因此trunc
andfloat
函数并不总是有效。我能够以不是最优雅的方式绕过它:
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
}
这模仿了在 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