在R中控制打印输出的小数位数

150

R中有一个选项可以控制数字的显示。例如:

options(digits=10)

该参数被设计为在 R 会话结束时以10个数字的形式给出计算结果。在 R 的帮助文件中,digits参数的定义如下:

digits: 控制数字值打印时要打印的位数。这只是一种建议。有效值为1到22,默认为7

所以,它只是个建议。如果我想始终显示10个数字,不多不少怎么办?

我的第二个问题是,如果我想显示超过22个数字,例如用于精确计算的100个数字,是否可以使用基本的R语言实现,还是需要额外的包/函数?

编辑:感谢jmoy的建议,我尝试了sprintf("%.100f",pi),得到了

[1] "3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000"

这个数有48位小数。这是 R 能处理的最大限制吗?


5
π的前15位数字是准确的。请与真实值进行比较:http://joyofpi.com/pi.html - Richie Cotton
1
你说得对。为什么在R中不同呢? - Mehper C. Palavuzlar
4
请参阅关于 R 的常见问题解答(FAQ):http://cran.r-project.org/doc/FAQ/R-FAQ.html#Why-doesn_0027t-R-think-these-numbers-are-equal_003f - Richie Cotton
2
Mehper:我认为你误解了R中数字的计算表示。你可能想阅读http://en.wikipedia.org/wiki/Floating_point。 - Shane
2
作为比较,Python 做了完全相同的事情:尝试 python -c "import math; print(format(math.pi, '.100f'))"。结果是 pi,有 48 个“真实”的小数位,其余 52 位填充了零。 - syntaxerror
4个回答

62
这只是一个建议,因为你可以很容易地编写一个忽略选项值的打印函数。内置的打印和格式化函数确实使用options值作为默认值。
至于第二个问题,由于R使用有限精度算术,因此您的答案在15或16位小数之外不准确,因此通常不需要更多。 gmprcdd包处理多精度算术(通过与gmp库的交互),但这主要涉及大整数而不是双精度小数的更多小数位。 MathematicaMaple将允许您提供任意数量的小数位。
编辑:
思考小数位和有效数字之间的区别可能会有所帮助。 如果您正在进行依赖于超出第15个有效数字的差异的统计测试,则您的分析几乎肯定是垃圾。
另一方面,如果您只处理非常小的数字,则这不是太大的问题,因为R可以处理尽可能小的数字 .Machine $ double.xmin (通常为2e-308)。
比较这两个分析。
x1 <- rnorm(50, 1, 1e-15)
y1 <- rnorm(50, 1 + 1e-15, 1e-15)
t.test(x1, y1)  #Should throw an error

x2 <- rnorm(50, 0, 1e-15)
y2 <- rnorm(50, 1e-15, 1e-15)
t.test(x2, y2)  #ok

在第一种情况下,数字之间的差异只会在许多有效数字之后才出现,因此数据"几乎恒定"。在第二种情况下,虽然数字之间的差异大小相同,但与数字本身的数量级相比,它们很大。

正如e3bo所提到的那样,您可以使用Rmpfr软件包来使用多精度浮点数。

mpfr("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825")

相较于正常(双精度)numeric向量,这些向量使用起来更慢且更占用内存,但如果你遇到了条件糟糕的问题或不稳定的算法,它们可能很有用。


4
这个Rwiki页面所示,Rmpfr包能够在R语言中进行高精度浮点数运算。 - e3bo
但是Rmpfr能被任何R包使用来提高其精度吗?还是它只能使用内部编码的函数? - skan
2
我也在想,“如果你进行的统计测试依赖于超出第15位有效数字的差异,那么你的分析几乎肯定是无用的。”但我不确定应该在多少位数字处得出结论,我认为是5,但如果有更好的建议我也很乐意接受。 - PatrickT

61

如果你是自己产生整个输出的话,可以使用 sprintf() 函数,例如:

> sprintf("%.10f",0.25)
[1] "0.2500000000"

该参数指定你想要使用十位小数格式化浮点数(在%.10f中,f代表浮点数,.10代表十位小数)。

我不知道是否有办法强制R的高级函数打印出固定数量的数字。

如果你打印R的普通数字,显示100个数字没有意义,因为使用64位双精度浮点数最高精度只能达到约16位小数(请查看系统上的.Machine$double.eps)。剩余的数字将会是垃圾数据。


实际上,我所使用的一些特殊卡方检验需要数百位小数才能给出准确的结果。此外,圆周率有成千上万个小数位。这就是为什么我对100位或更多位数字感到好奇的原因。 - Mehper C. Palavuzlar
15
π有无限多位小数,但这并不意味着计算机能够存储它们。 - Shane
我猜这是Mathematica比R更优越的场景。 - skan
2
@skan 你认为Mathematica存储了无限数量的小数吗? - Gregor Thomas
2
@Gregor 当然不是,但你可以使用尽可能多的数字,只要你的内存足够。 - skan

2
另外一种解决方案可以根据需要控制要打印出多少小数位(如果您不想打印冗余的零)。
例如,如果您有一个向量作为“元素”,并且想要得到它的总和。
elements <- c(-1e-05, -2e-04, -3e-03, -4e-02, -5e-01, -6e+00, -7e+01, -8e+02)
sum(elements)
## -876.5432

显然,最后一位数字被截断了,理想结果应该是-876.54321,但如果设置为固定的打印小数选项,例如sprintf("%.10f", sum(elements)),则会产生多余的零,如-876.5432100000
根据这里的教程:打印小数, 如果能够确定某个数字中有多少位小数,就像在-876.54321这里一样,需要打印5位小数,那么我们可以设置一个format函数的参数,如下所示:
decimal_length <- 5
formatC(sum(elements), format = "f", digits = decimal_length)
## -876.54321

我们可以根据每次查询更改“decimal_length”,以满足不同的十进制打印要求。

1
如果您主要使用 tibble,那么有一个函数可以强制保留数字:num()
以下是一个例子:
library(tidyverse)

data <- tribble(
  
~ weight, ~ weight_selfreport,
81.5,81.66969147005445,
72.6,72.59528130671505,
92.9,93.01270417422867,
79.4,79.4010889292196,
94.6,96.64246823956442,
80.2,79.4010889292196,
116.2,113.43012704174228,
95.4,95.73502722323049,
99.5,99.8185117967332
)

data <-
  data %>%
  mutate(across(where(is.numeric), ~ num(., digits = 3)))

data
#> # A tibble: 9 × 2
#>      weight weight_selfreport
#>   <num:.3!>         <num:.3!>
#> 1    81.500            81.670
#> 2    72.600            72.595
#> 3    92.900            93.013
#> 4    79.400            79.401
#> 5    94.600            96.642
#> 6    80.200            79.401
#> 7   116.200           113.430
#> 8    95.400            95.735
#> 9    99.500            99.819

因此,您甚至可以根据自己的需要决定不同的舍入选项。我认为这非常有帮助,并且是打印数据框的相当快速的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接