Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to format numbers in R, specifying the number of significant digits but keep significant zeroes and integer part?

I've been struggling with formatting numbers in R using what I feel are very sensible rules. What I would want is to specify a number of significant digits (say 3), keep significant zeroes, and also keep all digits before the decimal point, some examples (with 3 significant digits):

1.23456 -> "1.23"
12.3456 -> "12.3"
123.456 -> "123"
1234.56 -> "1235"
12345.6 -> "12346"
1.50000 -> "1.50"
1.49999 -> "1.50"

Is there a function in R that does this kind of formatting? If not, how could it be done?

I feel these are quite sensible formatting rules, yet I have not managed to find a function that formats in this way in R. As far as I googled this is not a duplicate of many similar questions such as this

Edit:

Inspired by the two good answers I put together a function myself that I believe works for all cases:

sign_digits <- function(x,d){
  s <- format(x,digits=d)
  if(grepl("\\.", s) && ! grepl("e", s)) {
    n_sign_digits <- nchar(s) - 
      max( grepl("\\.", s), attr(regexpr("(^[-0.]*)", s), "match.length") )
    n_zeros <- max(0, d - n_sign_digits)
    s <- paste(s, paste(rep("0", n_zeros), collapse=""), sep="")
  }
  s
}
like image 963
Rasmus Bååth Avatar asked Feb 14 '23 21:02

Rasmus Bååth


1 Answers

format(num,3) comes very close.

format(1.23456,digits=3)
# [1] "1.23"
format(12.3456,digits=3)
# [1] "12.3"
format(123.456,digits=3)
# [1] "123"
format(1234.56,digits=3)
# [1] "1235"
format(12345.6,digits=3)
# [1] "12346"
format(1.5000,digits=3)
# [1] "1.5"
format(1.4999,digits=3)
# [1] "1.5"

Your rules are not actually internally consistent. You want 1234.56 to round down to 1234, yet you want 1.4999 to round up to 1.5.

EDIT This appears to deal with the very valid point made by @Henrik.

sigDigits <- function(x,d){
  z <- format(x,digits=d)
  if (!grepl("[.]",z)) return(z)
  require(stringr)
  return(str_pad(z,d+1,"right","0"))
}

z <- c(1.23456, 12.3456, 123.456, 1234.56, 12345.6, 1.5000, 1.4999)
sapply(z,sigDigits,d=3)
# [1] "1.23"  "12.3"  "123"   "1235"  "12346" "1.50"  "1.50" 
like image 77
jlhoward Avatar answered Feb 16 '23 10:02

jlhoward