I want to format numbers in my reports to significant digits, but keep trailing significant zeroes and correctly format large numbers
For instance the numbers c(10.00001,12345,1234.5,123.45,1.2345,0.12345) to 3 significant digits should be 10.0, 12300, 1230, 123, 1.23, 0.123 but I get differing results with different methods (and none seem to work universaly.
> numbers<-c(10.00001,12345,1234.5,123.45,1.2345,0.12345)
> for(n in seq(numbers)){
+ print(signif(numbers[n],digits=3))
+ print(format(numbers[n],digits=3))
+ print(formatC(numbers[n], digits=3,format="fg"))
+ print(formatC(nu开发者_JAVA技巧mbers[n], digits=3,format="fg", flag="#"))
+ }
[1] 10
[1] "10"
[1] " 10"
[1] "10.0"
[1] 12300
[1] "12345"
[1] "12345"
[1] "12345."
[1] 1230
[1] "1234"
[1] "1234"
[1] "1234."
[1] 123
[1] "123"
[1] " 123"
[1] "123."
[1] 12.3
[1] "12.3"
[1] "12.3"
[1] "12.3"
[1] 1.23
[1] "1.23"
[1] "1.23"
[1] "1.23"
[1] 0.123
[1] "0.123"
[1] "0.123"
[1] "0.123"
Here, signif and format round the 10.00001 result. formatC with flag="#" correctly does the small numbers but not the large numbers.
Is there a better way ?
Sorry I never updated this at the time. None of the statements in my question, or prettynum worked. In the end I used
print(formatC(signif(numbers[n],digits=3), digits=3,format="fg", flag="#"))
which correctly coped with trailing zero's and big numbers.
Are you aware of prettyNum()
and all its options?
Another modification on Paul's answer. It appears that it also leaves a trailing decimal. I am removing it with gsub:
sigfig <- function(vec, digits){
return(gsub("\\.$", "", formatC(signif(vec,digits=digits), digits=digits, format="fg", flag="#")))
}
A more barebones option is options()
, which just does rounding. If you plan on doing this a lot, I suggest checking out Sweave.
> a <- 1.23456789
> options(digits=2)
> a
[1] 1.2
> options(digits=6)
> a
[1] 1.23457
If you like scientific notation
> format(2^31-1, scientific = TRUE, digits = 3)
[1] "2.15e+09"
Paul Hurley's method above worked well for me for both positive and negative numbers. Below is some code which modifies Paul's solution into a function in which the desired significant figures can be specified.
sigfig <- function(vec, n=3){
### function to round values to N significant digits
# input: vec vector of numeric
# n integer is the required sigfig
# output: outvec vector of numeric rounded to N sigfig
formatC(signif(vec,digits=n), digits=n,format="fg", flag="#")
} # end of function sigfig
to verify it works OK
numbers <- c(50000.01, 1000.001, 10.00001, 12345, 1234.5, 123.45, 1.2345, 0.12345, 0.0000123456, -50000.01, -1000.001,-10.00001, -12345, -1234.5, -123.45, -1.2345, -0.12345, -0.0000123456)
sigfig(numbers) # defaults to 3
sigfig(numbers, 3)
sigfig(numbers, 1)
sigfig(numbers, 6)
The following option replicates the format of formatC(format="fg",flag="#")
(fg
is a special version of f
where the digits specify significant digits and not digits after the decimal point, and the #
flag causes fg
to not drop trailing zeroes):
> f=2;x=c(10000.0001,1111,111.11,11.1,1.1,1.99,.01,.001,0,-.11,-.9,-.000011)
> dig=abs(pmin(0,floor(log10(abs(x)))-f+1))
> sprintf(paste0("%.",ifelse(is.infinite(dig),0,dig),"f"),x)
[1] "10000" "1111" "111" "11" "1.1" "2.0"
[7] "0.010" "0.0010" "0" "-0.11" "-0.90" "-0.000011"
> sub("\\.$","",formatC(x,f,,"fg","#"))
[1] "10000" "1111" "111" "11" "1.1" "2.0"
[7] "0.010" "0.0010" "0" "-0.11" "-0.90" "-0.000011"
I found a potentially unwanted behaviour with the answer presented by PaulHurleyuk:
Tests
Test 1:
numbers <- c(0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000)
print(formatC(signif(numbers, digits = 3), digits = 3, format = "fg", flag = "#"))
Returns:
[1] "0.000100" "0.00100" "0.0100" "0.100" "1.00" "10.0" "100." "1000."
Test 2:
numbers <- c(1.0001, 1.001, 1.01, 1.1, 11, 101, 1001, 10001)
print(formatC(signif(numbers,digits=3), digits=3,format="fg", flag="#"))
Returns:
[1] "1.00" "1.00" "1.01" "1.10" "11.0" "101." "1000." "10000."
Notice the trailing decimal delimiters in both examples and also the introduced trailing zeros in test 1.
Solution
To remove the trailing decimal delimiters:
gsub("\\.$", "", formatC(signif(numbers, digits = 3), digits = 3,format = "fg", flag = "#"))
If used often, make it a function:
sigfill <- function(x, sigfigs = 3){
out <- gsub("\\.$", "",
formatC(signif(x, digits = sigfigs),
digits = sigfigs, format = "fg", flag = "#"))
return(out)
}
To also remove trailing zeros introduced by the previous code:
sigfill <- function(x, sigfigs = 3){
out <- gsub("\\.$", "",
formatC(signif(x, digits = sigfigs),
digits = sigfigs, format = "fg", flag = "#"))
out[grepl(".", out, fixed = TRUE)] <- strtrim(out[grepl(".", out, fixed = TRUE)],
sigfigs + c(1, 2)[grepl("-", out, fixed = TRUE) + 1])
return(out)
}
Test again
Positive numbers:
numbers <- c(0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000)
sigfill(numbers)
returns
[1] "0.00" "0.00" "0.01" "0.10" "1.00" "10.0" "100" "1000"
"Spread out" numbers:
numbers <- c(1.0001, 1.001, 1.01, 1.1, 11, 101, 1001, 10001)
sigfill(numbers)
returns
[1] "1.00" "1.00" "1.01" "1.10" "11.0" "101" "1000" "10000"
Negative numbers:
numbers <- c(-0.0001, -0.001, -0.01, -0.1, -1, -10, -100, -1000)
sigfill(numbers)
returns
[1] "-0.00" "-0.00" "-0.01" "-0.10" "-1.00" "-10.0" "-100" "-1000"
Result: No trailing decimal delimiters or additional trailing zeros.
精彩评论