问题
I have a nested list containing numbers, for example
x <- list(1 + .Machine$double.eps, list(rnorm(2), list(rnorm(1))))
If I call as.character
on this, all the numbers are given in fixed format, to 15 significant digits.
as.character(x)
## [1] "1"
## [2] "list(c(0.654345721043012, 0.611306113713901), list(-0.278722330674071))"
I'd like to be able to control how the numbers are formatted. At the very least, I'd like to be able to control how many significant figures are included. As a bonus, being able to specify scientific formatting rather than fixed formatting would be nice.
The ?as.character
help page states:
as.character represents real and complex numbers to 15 significant digits (technically the compiler's setting of the ISO C constant DBL_DIG, which will be 15 on machines supporting IEC60559 arithmetic according to the C99 standard). This ensures that all the digits in the result will be reliable (and not the result of representation error), but does mean that conversion to character and back to numeric may change the number. If you want to convert numbers to character with the maximum possible precision, use format.
So it doesn't appear to be possible to change the formatting using as.character
directly.
Calling format
destroys the list structure:
format(x, digits = 5)
## [1] "1" "0.65435, 0.61131, -0.27872"
formatC
throws an error about not supporting list inputs.
deparse
also doesn't allow users to change how numbers are formatted: as.character(x)
is the same as vapply(x, deparse, character(1))
.
This is almost correct, but there are extra double-quote characters around the numbers that I don't want:
as.character(rapply(x, format, digits = 5, how = "list"))
## [1] "1"
## [2] "list(c(\"0.65435\", \"0.61131\"), list(\"-0.27872\"))"
How do I control the formatting of the numbers?
A partial solution: for reducing the number of significant figures, I can adapt the previous example by converting to character using format, then back to numeric.
as.character(rapply(x, function(x) as.numeric(format(x, digits = 5)), how = "list"))
## [1] "1" "list(c(-1.0884, 1.6892), list(0.58783))"
This doesn't work if I want to increase the number of sig figs beyond 15 or use scientific formatting (since we run into the limitation of as.character
).
as.character(rapply(x, function(x) as.numeric(format(x, digits = 22)), how = "list"))
## [1] "1"
## [2] "list(c(-1.08842504028146, 1.68923191896784), list(0.5878275490431))"
回答1:
Play with the how
argument to rapply()
:
> rapply(x, sprintf, fmt = "%0.5f", how = "replace")
[[1]]
[1] "1.00000"
[[2]]
[[2]][[1]]
[1] "0.18041" "-0.63925"
[[2]][[2]]
[[2]][[2]][[1]]
[1] "0.14309"
For more digits, change fmt
:
> rapply(x, sprintf, fmt = "%0.22f", how = "replace")
[[1]]
[1] "1.0000000000000002220446"
[[2]]
[[2]][[1]]
[1] "1.2888001496908956244880" "1.0289289081633956612905"
[[2]][[2]]
[[2]][[2]][[1]]
[1] "0.4656598705611921240610"
You can gsub()
out the quotes:
> gsub("\"", "", deparse(rapply(x, function(z) sprintf(fmt = "%0.22f", z), how = "replace")))
[1] "list(1.0000000000000002220446, list(c(1.2888001496908956244880, "
[2] "1.0289289081633956612905), list(0.4656598705611921240610)))"
回答2:
Advice given to me by R Core member Martin Maechler was that you can format the numbers in a "%g17"
style (that is R decides whether fixed or scientific formatting is best, and increases the number of significant digits to 17; see ?sprintf
) by using deparse and the "digits17"
controls option. The latter is documented on the ?.deparseOpts
help page.
vapply(x, deparse, character(1), control = "digits17")
来源:https://stackoverflow.com/questions/37025196/how-do-you-control-the-formatting-of-digits-when-converting-lists-of-numbers-to