Curious output using formatC with 2 significant digits

361 views Asked by At

I want to format figures with 2 significant digits using formatC. But it has a strange behaviour. Here are the figures:

(x <- data.frame(  cil = c(1.234, 0.444, 0.712, 0.999, 1.999)
                 , ciu = c(1.812, 1.234, 0.999, 1.199, 2.690)
                 )
 )
 
x$ci <- with(x,paste("("
              , formatC(cil, format="g", digits=2, flag="#")
              , "-"
              , formatC(ciu, format="g", digits=2, flag="#")
              ,")"
                      )
              )
x

And here are the results:

      cil   ciu         ci
1     1.234 1.812  ( 1.2 - 1.8 )
2     0.444 1.234 ( 0.44 - 1.2 )
3     0.712 0.999 ( 0.71 - 1.0 )
4     0.999 1.199  ( 1.0 - 1.2 )
5     1.999 2.690  (  2. - 2.7 )

In case 5 I expected 2.0 and not 2.. Is there an explanation for this? Did I something wrong with the definition of the parameters?

New curious behaviour: leading space depending if figure was rounded down or up:

y1 <- 18.96552
y2 <- 17.04545
formatC(y1, format="g", digits=2,flag="#")
[1] "  19."
formatC(y2, format="g", digits=2,flag="#")
"17."

Can be solved with trim (from gdata). But anyway, it is a strange behaviour as the first one, which by the way persists (V4.32).

2

There are 2 answers

5
Cath On BEST ANSWER

To illustrate what I was saying in my comment, you can do :

x$ci<-with(x,paste("(",
                   format(cil,digits=2,nsmall=2),
                   "-",
                   format(ciu,digits=2,nsmall=2),")"))
> x
  case   cil   ciu              ci
1    A 1.234 1.812 ( 1.23 - 1.81 )
2    B 0.444 1.234 ( 0.44 - 1.23 )
3    C 0.712 0.999 ( 0.71 - 1.00 )
4    D 0.999 1.199 ( 1.00 - 1.20 )
5    E 1.999 2.690 ( 2.00 - 2.69 )

or the following, to suppress the spaces before or after the brackets :

x$ci<-with(x,paste0("(",
                    format(cil,digits=2,nsmall=2),
                    " - ",
                    format(ciu,digits=2,nsmall=2),")"))
> x
  case   cil   ciu          ci
1    A 1.234 1.812 (1.23 - 1.81)
2    B 0.444 1.234 (0.44 - 1.23)
3    C 0.712 0.999 (0.71 - 1.00)
4    D 0.999 1.199 (1.00 - 1.20)
5    E 1.999 2.690 (2.00 - 2.69)

NB : you actually can get the same result using function formatC but with format="f" instead of "g".

UPDATE :

I guess the fact that 0 is not printed after 2. is just a bug in some R versions (weirder thing : if you try the line with 2.01 instead of 1.999, you'll get "2.0"...).

To make it work with your line and obtain exactly what you want, just add round function :

x$ci<-with(x,paste("(",
                    formatC(round(cil,2), format="g", digits=2, flag="#"),
                   "-",
                   formatC(round(ciu,2), format="g", digits=2, flag="#"),")"))

> x
  case   cil   ciu             ci
1    A 1.234 1.812  ( 1.2 - 1.8 )
2    B 0.444 1.234 ( 0.44 - 1.2 )
3    C 0.712 0.999 ( 0.71 - 1.0 )
4    D 0.999 1.199  ( 1.0 - 1.2 )
5    E 1.999 2.690  ( 2.0 - 2.7 )
3
akrun On

Using R 3.1.2 on linux mint 17, I couldn't reproduce the problem as I am getting the exact result as your expected output. But, here is an option to use paste along with do.call in case you have many columns (or in general)

1) Using formatC

x$ci <- paste0("(",do.call(`paste`, c(lapply(x[,2:3], function(x) 
 formatC(x, format='g',   digits=2, flag='#')), list(sep=" - "))) ,")")
x$ci
#[1] "(1.2 - 1.8)"  "(0.44 - 1.2)" "(0.71 - 1.0)" "(1.0 - 1.2)"  "(2.0 - 2.7)" 

Note: that the above is exactly the same expected output.

2) Using sprintf

Another option that I consider would be to use sprintf if you need similar output as @CathG showed before the update

x$ci <- paste0("(",do.call(`paste`, c(lapply(x[2:3], function(x) 
                       sprintf('%0.2f', x)), list(sep="-"))),")")
x$ci
#[1] "(1.23-1.81)" "(0.44-1.23)" "(0.71-1.00)" "(1.00-1.20)" "(2.00-2.69)"

Update

You could use regex to solve the problem. For example, I created the 5th entry as the same as your output and use regex lookbehind

x$ci[5] <- "( 2. - 2.7 )"
sub('(?<=\\.) ', '0', x$ci, perl=TRUE)
#[1] "( 1.2 - 1.8 )"  "( 0.44 - 1.2 )" "( 0.71 - 1.0 )" "( 1.0 - 1.2 )" 
#[5] "( 2.0- 2.7 )"