假设我们有一个数字1.000633,我想要计算小数点后第一个非零数字出现前的零的数量,答案应该是3。对于0.002,答案应该是2。
在R中没有这样的函数可以帮助。我已经在DescTools软件包中探索了Ndec函数,但它不能胜任这项任务。
在R中没有这样的函数可以帮助。我已经在DescTools软件包中探索了Ndec函数,但它不能胜任这项任务。
使用 regexpr
及其 match.length
参数
attr(regexpr("(?<=\\.)0+", x, perl = TRUE), "match.length")
这里有另一个可能性:
zeros_after_period <- function(x) {
if (isTRUE(all.equal(round(x),x))) return (0) # y would be -Inf for integer values
y <- log10(abs(x)-floor(abs(x)))
ifelse(isTRUE(all.equal(round(y),y)), -y-1, -ceiling(y))} # corrects case ending with ..01
示例:
x <- c(1.000633, 0.002, -10.01, 7.00010001, 62.01)
sapply(x,zeros_after_period)
#[1] 3 2 1 3 1
ifelse(round(y) == y, -y-1, -ceiling(y))
? - David Arenburgx <- c(0.1, 1.0, 1.001)
。 - David Arenburgy = log10(abs(x) %% 1)
似乎也可以工作。为了使它向量化,y = -log10(abs(x) %% 1); ceiling(y) - ( (y %% 1) < 10^-options()$digits )
或者使用其他阈值,我猜想。可能仍有一两个边缘情况。 - Franksub
。ifelse(grepl("\\.0", str1),
nchar(sub("[^\\.]+\\.(0+)[^0]+.*", "\\1", str1)), NA)
#[1] 3 2 3 3 2
stringi
。library(stringi)
r1 <- stri_extract(str1, regex="(?<=\\.)0+")
ifelse(is.na(r1), NA, nchar(r1))
#[1] 3 2 3 3 2
只是为了检查它是否适用于任何奇怪的情况
str2 <- "0.00A-Z"
nchar(sub("[^\\.]+\\.(0+)[^0]+.*", "\\1", str2))
#[1] 2
str1 <- as.character(c(1.000633, 0.002, 0.000633,
10.000633, 3.0069006))
"[^\\.]+\\.(0+)[^0]{1}.*"
,这样就可以解决问题了(尽管我仍然更喜欢RHertel的“numeric”方法)。这是准确解决问题的问题,而不是点赞。 - Cathrle
函数:#test values
x <- c(0.000633,0.003,0.1,0.001,0.00633044,10.25,111.00012,-0.02)
#result
sapply(x, function(i){
myNum <- unlist(strsplit(as.character(i), ".", fixed = TRUE))[2]
myNumRle <- rle(unlist(strsplit(myNum, "")))
if(myNumRle$values[1] == 0) myNumRle$lengths[1] else 0
})
#output
# [1] 3 2 0 2 2 0 3 1
stringr
包中的 str_count
,可以另一种方式实现。 x <- as.character(1.000633)
str_count(gsub(".*[.]","",x), "0")
#[1] 3
编辑:这个计算方式会统计小数点后面所有的零,直到遇到第一个非零值。
y <- c(1.00215, 1.010001, 50.000809058, 0.1)
str_count(gsub(".*[.]","",gsub("(?:(0+))[1-9].*","\\1",as.character(y))),"0")
#[1] 2 1 3 0
floor( -log10( eps + abs(x) - floor( abs( x ) ) ) )
count0 <- function(x, tol = .Machine$double.eps ^ 0.5) { x <- abs(x); y <- -log10(x - floor(x)); floor(y) - (y %% 1 < tol) }
- Rolandleading_zero <- function(x) {
if (x < 0.001){
x <- as.character(format(x,scientific=FALSE))
}
nlead <- attr(regexpr("(?<=\\.)0+|$", x, perl = TRUE), "match.length") # leading zeros
nlead
}
你可以使用sub
,因为我们不需要跳跃。因此不需要使用gsub
nchar(sub(".*\\.(0*).*","\\1",str1))
[1] 3 2 3 3 2
在哪里
str1 <- as.character(c(1.000633, 0.002, 0.000633,
10.000633, 3.0069006))
ceiling()
函数而不是floor()
函数,然后再减去1,您就不会遇到1*10**x这样的数字问题,比如(0.1, 0.01, 0.001, ...)。x |> # input vector of numeric values
abs() %% # take the absolute value (delete sign of numbers)
1 |> # do numbers modulo 1
# (delete everything before the decimal point)
log10() |> # use log10 to count the numbers after the period
abs() |> # flip sign, as we want the positive numbers
ceiling() - # take the ceiling of the numbers.
# this will solve the 1*10**x issue
1 # substract 1 since we actually
# wanted the floor of the values
数据:
x <- c(0.000633,0.003,0.1,0.001,0.00633044,10.25,111.00012,-0.02)
# [1] 3 2 0 2 2 0 3 1
x <- 10.2
,这个返回的是 -1 而不是 0。我不得不在我的解决方案中插入一个ifelse
语句来捕获一个会在没有它的情况下失败的情况。这可能是你认为我的实现复杂的原因。另一方面,也许你可以考虑捕获这种情况,这样你的解决方案也适用于任何数字。 - RHertel-1
表示没有匹配。这是“regexpr”未匹配的符号。我的解决方案适用于任何数字。 - David Arenburg(?<=\\.)0+|$
作为正则表达式即可。 - maaartinus