根据小数点前位数的不同舍入规则
Different rounding rule based on number of digits before the decimal
假设我们有以下数值向量:
y=c(0.111,1.11,11.1,111.1)
我希望它四舍五入如下:
0.11,1.11,11.1,111
这个规则很简单:一共要三位数!但如果数字很大(例如 1111 或 11111),则保留所有数字,但不带任何小数。
当然,必须有一个更简单的解决方案?:
lapply(y,function(x){
ifelse(nchar(as.integer(x))<1,round(x,digits=3),
ifelse(nchar(as.integer(x))==1,round(x,digits=2),
ifelse(nchar(as.integer(x))==2,round(x,digits=1),
ifelse(nchar(as.integer(x))>2,round(x,digits=0)
))))
}
)
这个有用吗?
y <- c(0.111,1.11,11.1,111.1,1111,11111)
(ry <- gsub("0+$","",round(y*100)/100))
## [1] "0.11" "1.11" "11.1" "111.1" "1111" "11111"
as.numeric(ry)
## [1] 0.11 1.11 11.10 111.10 1111.00 11111.00
我一般不喜欢转换为字符的解决方案,但它似乎可以做你想做的事......(请注意,这个 rounds 是你想要的,但是打印的数值重新包括零值:cat(ry,"\n")
将按原样打印出数字)
只需使用signif
:
y <- c(0.111,1.11,11.1,111.1,1111)
signif(y, pmax(3,trunc(log10(y)+1)))
#[1] 0.111 1.110 11.100 111.000 1111.000
pmax(...)
部分说明了数字在小数点前有 4 位或更多位的情况(log10
只是计算这些数字的一种方式)。
不清楚问题是关于漂亮打印(结果是字符)还是舍入(结果是数字)。
如果问题是关于转换为漂亮打印的字符,可以使用 sprintf()
函数。
sprintf()
函数理解转换说明符 g
,其中可以指定 有效数字 的数目。但是,它并未涵盖整个值范围。因此,必须根据 y
:
的大小使用不同的转换说明符
y <- c(0.0111, 0.111, 1.11, 11.1, 111.1, 1111, 11111)
sprintf(c("%3.2f", "%3.3g", "%3.0f")[cut(y, c(0, 1, 1000, Inf))], y)
[1] "0.01" "0.11" "1.11" "11.1" "111" "1111" "11111"
如果问题是关于数值的舍入:
round(y, c(2, 1, 0)[cut(y, c(0, 10, 100, Inf))])
[1] 0.01 0.11 1.11 11.10 111.00 1111.00 11111.00
说明
c("%3.2f", "%3.3g", "%3.0f")[cut(y, c(0, 1, 1000, Inf))]
是嵌套 ifelse()
的替代品,以便为每个 y
:
选择正确的转换说明符
[1] "%3.2f" "%3.2f" "%3.3g" "%3.3g" "%3.3g" "%3.0f" "%3.0f"
cut()
将数字转换为因子。它将 y
的范围划分为区间,并根据它们属于哪个区间对 y
中的值进行编码。最左边的间隔对应于第一级,下一个最左边的间隔对应于第二级,依此类推。 (来自 help("cut")
)。
然后,根据y
的值,使用级别数对转换说明符向量进行子集化,以选择合适的说明符。
在写解释的时候,有一个稍微不同的方法。我们可以直接使用级别的标签,而不是使用级别编号对转换说明符的向量进行子集化:
sprintf(as.character(cut(y, c(0, 1, 1000, Inf), labels = c("%3.2f", "%3.3g", "%3.0f"))), y)
[1] "0.01" "0.11" "1.11" "11.1" "111" "1111" "11111"
假设我们有以下数值向量:
y=c(0.111,1.11,11.1,111.1)
我希望它四舍五入如下:
0.11,1.11,11.1,111
这个规则很简单:一共要三位数!但如果数字很大(例如 1111 或 11111),则保留所有数字,但不带任何小数。
当然,必须有一个更简单的解决方案?:
lapply(y,function(x){
ifelse(nchar(as.integer(x))<1,round(x,digits=3),
ifelse(nchar(as.integer(x))==1,round(x,digits=2),
ifelse(nchar(as.integer(x))==2,round(x,digits=1),
ifelse(nchar(as.integer(x))>2,round(x,digits=0)
))))
}
)
这个有用吗?
y <- c(0.111,1.11,11.1,111.1,1111,11111)
(ry <- gsub("0+$","",round(y*100)/100))
## [1] "0.11" "1.11" "11.1" "111.1" "1111" "11111"
as.numeric(ry)
## [1] 0.11 1.11 11.10 111.10 1111.00 11111.00
我一般不喜欢转换为字符的解决方案,但它似乎可以做你想做的事......(请注意,这个 rounds 是你想要的,但是打印的数值重新包括零值:cat(ry,"\n")
将按原样打印出数字)
只需使用signif
:
y <- c(0.111,1.11,11.1,111.1,1111)
signif(y, pmax(3,trunc(log10(y)+1)))
#[1] 0.111 1.110 11.100 111.000 1111.000
pmax(...)
部分说明了数字在小数点前有 4 位或更多位的情况(log10
只是计算这些数字的一种方式)。
不清楚问题是关于漂亮打印(结果是字符)还是舍入(结果是数字)。
如果问题是关于转换为漂亮打印的字符,可以使用 sprintf()
函数。
sprintf()
函数理解转换说明符 g
,其中可以指定 有效数字 的数目。但是,它并未涵盖整个值范围。因此,必须根据 y
:
y <- c(0.0111, 0.111, 1.11, 11.1, 111.1, 1111, 11111)
sprintf(c("%3.2f", "%3.3g", "%3.0f")[cut(y, c(0, 1, 1000, Inf))], y)
[1] "0.01" "0.11" "1.11" "11.1" "111" "1111" "11111"
如果问题是关于数值的舍入:
round(y, c(2, 1, 0)[cut(y, c(0, 10, 100, Inf))])
[1] 0.01 0.11 1.11 11.10 111.00 1111.00 11111.00
说明
c("%3.2f", "%3.3g", "%3.0f")[cut(y, c(0, 1, 1000, Inf))]
是嵌套 ifelse()
的替代品,以便为每个 y
:
[1] "%3.2f" "%3.2f" "%3.3g" "%3.3g" "%3.3g" "%3.0f" "%3.0f"
cut()
将数字转换为因子。它将 y
的范围划分为区间,并根据它们属于哪个区间对 y
中的值进行编码。最左边的间隔对应于第一级,下一个最左边的间隔对应于第二级,依此类推。 (来自 help("cut")
)。
然后,根据y
的值,使用级别数对转换说明符向量进行子集化,以选择合适的说明符。
在写解释的时候,有一个稍微不同的方法。我们可以直接使用级别的标签,而不是使用级别编号对转换说明符的向量进行子集化:
sprintf(as.character(cut(y, c(0, 1, 1000, Inf), labels = c("%3.2f", "%3.3g", "%3.0f"))), y)
[1] "0.01" "0.11" "1.11" "11.1" "111" "1111" "11111"