如何确定 R 中数据中有效数字的数量?

How do I determine the number of significant figures in data in R?

我有一个正在用 R 分析的大型数据集,我对信息的一列或向量感兴趣。该向量中的每个条目都有不同数量(从 1-5 不等)的有效数字,我想对该向量进行子集化,这样我就看不到只有一个有效数字的数据。我可以使用什么样的测试或函数来让 R 报告每个条目的有效数字的数量?我查看了 signif() 函数,但它更多的是用于将数据四舍五入到指定数量的有效数字,而不是查询那里有多少个 sig figs。

示例:假设我有这个向量:
4
28.382
120
82.3
100
30.0003

我想删除只有一位有效数字的条目。那将是条目 1(值为 4)和条目 5(值为 100)。我知道如何在 R 中对数据进行子集化,但我不知道如何告诉 R "find" 所有值只有一个有效数字。

x <- c(4, 28.382, 120, 82.3, 100, 30.0003)
#compare the values with result of signif
#you need to consider floating point precision
keep <- abs(signif(x, 1) - x) > .Machine$double.eps
x[keep]
#[1]  28.3820 120.0000  82.3000  30.0003

我认为这应该等同于罗兰的解决方案。

x <- c(4, 4.0, 4.00, 28.382, 120,
       82.3, 100, 100.0, 30.0003)
x
ifelse(x == signif(x, 1), NA, x)
ifelse(x == signif(x, 2), NA, x)
ifelse(x == signif(x, 3), NA, x)

无论如何,对于“4.00”和“100.0”这样的情况,它至少有同样的问题,即给出不正确的有效数字位数。

如上所述,部分解决方案是将数字视为字符串。仅仅将数字转换为字符是不够的,它们必须照原样读入,这需要一点小心。 read.table 函数组 can come in handy 中的 colClasses 参数 can come in handy.

xc <- c("4", "4.0", "4.00", "28.382", "120",
        "82.3", "100", "100.0", "30.0003")
xc
# "4"  "4.0" "4.00" "28.382" "120" "82.3" "100" "100.0" "30.0003"
ifelse(xc == signif(as.numeric(xc), 1), NA, xc)
# "NA" "4.0" "4.00" "28.382" "120" "82.3" "NA"  "100.0" "30.0003"

只删除了“4”和“100”。这看起来很有希望,但如果我们走得更远一点,我们就会发现并非一切都像它应该的那样。

ifelse(xc == signif(as.numeric(xc), 2), NA, xc)
# "NA" "4.0" "4.00" "28.382" "120" "82.3" "NA"  "100.0" "30.0003"
ifelse(xc == signif(as.numeric(xc), 3), NA, xc)
# "NA" "4.0" "4.00" "28.382" "120" "82.3" "NA"  "100.0" "30.0003"

原因可以这样论证

2 == "2"
# TRUE – only what's between the quotes is compared
2.0 == "2"; 02 == "2"
# TRUE
# TRUE – R removes what's considered numerically empty characters
2 == "2.0"
# FALSE – strings aren't modified.
2 == as.numeric("2.0")
# TRUE – that is, unless you explicitly request it.

同样值得记住的是,字符串的比较是基于字母数字顺序的,即使字符串很容易被解释为数字。

2 < "2.0"
# TRUE
2 > "2.0"
# FALSE
"2.0" < "2.00"
# TRUE
sort(xc)
# "100" "100.0" "120" "28.382" "30.0003" "4" "4.0" "4.00" "82.3" 

到目前为止,我为这个问题找到的唯一完整修复方法有点老套。它包括分离出包含小数点分隔符 (“.”) 的字符串,并将这些字符串的最后一个字符替换为“1”(或任何非零数字)。从而将“4.0”变成“4.1”,但保留“100”原样。然后将这个新向量用作比较的基础。

xc.1 <- xc
decimal <- grep(".", xc, fixed=TRUE)
xc.1[decimal] <- gsub(".$", "1", xc[decimal])
xc.1 <- as.numeric(xc.1)

xc
# "4"  "4.0" "4.00" "28.382" "120" "82.3" "100" "100.0" "30.0003"
ifelse(xc.1 == signif(xc.1, 1), NA, xc)
# "NA" "4.0" "4.00" "28.382" "120" "82.3" "NA"  "100.0" "30.0003"
ifelse(xc.1 == signif(xc.1, 2), NA, xc)
# "NA" "NA"  "4.00" "28.382" "NA"  "82.3" "NA"  "100.0" "30.0003"
ifelse(xc.1 == signif(xc.1, 3), NA, xc)
# "NA" "NA"  "NA"   "28.382" "NA"  "NA"   "NA"  "100.0" "30.0003"

如果你想实际计算有效数字的个数,可以用一个小循环来完成。

n <- 7

# true counts
xc.count <- vector(length=length(xc.1))
for (i in n:1) xc.count[xc.1 == signif(xc.1, i)] <- i
xc.count
# 1 2 3 5 2 3 1 4 6

# simple counts
x.count <- vector(length=length(x))
for (i in n:1) x.count[x == signif(x, i)] <- i
x.count
# 1 1 1 5 2 3 1 1 6