如何返回R中的小数位数

如何返回R中的小数位数,r,R,我在R工作。我有一系列以十进制度数表示的坐标,我想根据这些数字的小数位数对这些坐标进行排序(即,我想放弃小数位数太少的坐标)。 R中是否有一个函数可以返回一个数字的小数位数,我可以将其合并到函数编写中? 输入示例: AniSom4 -17.23300000 -65.81700 AniSom5 -18.15000000 -63.86700 AniSom6 1.42444444 -75.86972 AniSom7

我在R工作。我有一系列以十进制度数表示的坐标,我想根据这些数字的小数位数对这些坐标进行排序(即,我想放弃小数位数太少的坐标)。
R中是否有一个函数可以返回一个数字的小数位数,我可以将其合并到函数编写中?
输入示例:

AniSom4     -17.23300000        -65.81700

AniSom5     -18.15000000        -63.86700

AniSom6       1.42444444        -75.86972

AniSom7       2.41700000        -76.81700

AniLac9       8.6000000        -71.15000

AniLac5      -0.4000000        -78.00000

理想情况下,我会编写一个脚本,丢弃AniLac9和Anilac5,因为这些坐标记录的精度不够。我想放弃经度和纬度都少于3个非零十进制值的坐标。

在[R]中,2.30000和2.3之间没有差异,都被舍入到2.3,因此如果你想检查的话,一个比另一个精度不高。另一方面,如果这不是你的意思:如果你真的想这样做,你可以使用1)乘以10,2)使用floor()函数3)除以10 4)检查是否与原始值相等。(但是请注意,比较浮点值是否相等是一种不好的做法,请确保这是您真正想要的)

您可以轻松地为任务编写一个小函数,例如:

decimalplaces <- function(x) {
    if ((x %% 1) != 0) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed=TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}

更新(2018年4月3日)以解决@owen88关于双精度浮点数舍入错误的报告——替换
x%%1
检查:

decimalplaces <- function(x) {
    if (abs(x - round(x)) > .Machine$double.eps^0.5) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed = TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}
decimalplaces.Machine$double.eps^0.5){
nchar(strsplit(sub('0+$,'',as.character(x)),”,fixed=TRUE)[[1]][[2]]
}否则{
返回(0)
}
}

这里有一种方法。它检查小数点后的前20位,但如果您有其他想法,可以调整数字20

x <- pi
match(TRUE, round(x, 1:20) == x)

根据罗曼的建议进行调整:

num.decimals <- function(x) {
    stopifnot(class(x)=="numeric")
    x <- sub("0+$","",x)
    x <- sub("^.+[.]","",x)
    nchar(x)
}
x <- "5.2300000"
num.decimals(x)

num.decimals对于普通应用程序,下面是对daroczig代码的修改,以处理向量:

decimalplaces <- function(x) {
    y = x[!is.na(x)]
    if (length(y) == 0) {
      return(0)
    }
    if (any((y %% 1) != 0)) {
      info = strsplit(sub('0+$', '', as.character(y)), ".", fixed=TRUE)
      info = info[sapply(info, FUN=length) == 2]
      dec = nchar(unlist(info))[seq(2, length(info), 2)]
      return(max(dec, na.rm=T))
    } else {
      return(0)
    }
}

我们现在有多少个小数?

有趣的问题。这里是对上述受访者工作的另一个调整,矢量化,并扩展到处理小数点左侧的数字。针对负数进行测试,这将为以前的
strsplit()
方法提供不正确的结果

如果希望只计算右侧的,则可以将
trailingonly
参数设置为
TRUE

nd1 <- function(xx,places=15,trailingonly=F) {
  xx<-abs(xx); 
  if(length(xx)>1) {
    fn<-sys.function();
    return(sapply(xx,fn,places=places,trailingonly=trailingonly))};
  if(xx %in% 0:9) return(!trailingonly+0); 
  mtch0<-round(xx,nds <- 0:places); 
  out <- nds[match(TRUE,mtch0==xx)]; 
  if(trailingonly) return(out); 
  mtch1 <- floor(xx*10^-nds); 
  out + nds[match(TRUE,mtch1==0)]
}
字符串版本在15位处被截断(实际上,不确定为什么另一个的places参数被截断了1位…超出它的原因是它在两个方向上都计算数字,因此如果数字足够大,它的大小可能会增加一倍)。
as.character()
可能有一些格式化选项,可以为
nd2()
提供一个与
nd1()的
places
参数等价的选项

nd1()
更快

rowSums(replicate(10,system.time(replicate(100,nd1(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0))))));
rowSums(replicate(10,system.time(replicate(100,nd2(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0))))));

我不是想劫持线程,只是把它发布在这里,因为它可能会帮助某人处理我试图用建议的代码完成的任务

不幸的是,即使是@daroczig的解决方案,我也无法检查一个数字是否少于8位小数

@daroczig的代码:

decimalplaces <- function(x) {
    if (abs(x - round(x)) > .Machine$double.eps^0.5) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed = TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}
等等

到目前为止,我们能够使用以下笨拙的代码完成所需的测试:

if (abs(x*10^8 - floor(as.numeric(as.character(x*10^8)))) > .Machine$double.eps*10^8) 
   {
   print("The number has more than 8 decimal digits")
   }

PS:我可能遗漏了一些关于不取
.Machine$double.eps
的根的内容,因此请小心

另一个贡献,将其完全保留为数字表示,而不转换为字符:

countdecimals <- function(x) 
{
  n <- 0
  while (!isTRUE(all.equal(floor(x),x)) & n <= 1e6) { x <- x*10; n <- n+1 }
  return (n)
}

countdecimals基于daroczig函数的向量解决方案(也可以处理包含字符串和数字的脏列):


decimalplaces\u vec不确定为什么不使用上述简单方法(从tidyverse/magrittr加载管道)

因此R在内部似乎无法区分最初获得
1.000
1
。因此,如果一个人有一个各种十进制数的向量输入,通过取小数位数的最大值,可以看到它最初有(至少)多少个数字


编辑:修复了错误

如果这里有人需要上面Gergely Daróczi提供的函数的矢量化版本:

decimalplaces <- function(x) {
  ifelse(abs(x - round(x)) > .Machine$double.eps^0.5,
         nchar(sub('^\\d+\\.', '', sub('0+$', '', as.character(x)))),
         0)
}

decimalplaces(c(234.1, 3.7500, 1.345, 3e-15))
#> 1 2 3 0
decimalplaces.Machine$double.eps^0.5,
nchar(sub('^\\d+\\.','',sub('0+$','',as.character(x)),
0)
}
小数位数(c(234.1,3.7500,1.345,3e-15))
#> 1 2 3 0

我已经测试了一些解决方案,我发现这一解决方案对其他解决方案中报告的错误非常有效

countDecimalPlaces <- function(x) {
  if ((x %% 1) != 0) {
    strs <- strsplit(as.character(format(x, scientific = F)), "\\.")
    n <- nchar(strs[[1]][2])
  } else {
    n <- 0
  }
  return(n) 
}

# example to prove the function with some values
xs <- c(1000.0, 100.0, 10.0, 1.0, 0, 0.1, 0.01, 0.001, 0.0001)
sapply(xs, FUN = countDecimalPlaces)

countDecimalPlaces数据文件中的小数位数是如何记录的?例如,它可能同时有34.4和34.400,这些会被认为是不同的吗?示例输入和所需输出将很有帮助;小数位数在x86和其他主流处理器中无法准确表示。除了文本表示法,你会得到虚假的结果。或者将数据作为字符导入,计算“点”后面的字符数,并将其作为排序标准。我喜欢这个外观。非常感谢你的帮助!谢谢你@Pascal!我刚刚意识到我在函数中有一个输入错误(在
as.character
函数中写了'num'而不是'x'),我已经纠正了这个错误。此外,我还添加了regexpr部分,因此数字/字符串末尾的零将自动删除。此函数非常有用,但是当给定一个数字(如63.0000)时,它会返回一个错误。有没有办法修改它,使其在这些情况下返回0?@schnee感谢您的反馈。或者,您可以将
选项(scipen=999)
设置为不使用科学格式。
as.character
不好——改用
sprintf
<代码>as。字符
对于小/大“整数”数字(如1e6、1e-6)将失败。好主意!我想一定还有一个错误:
decimalplaces2(c(1.2,2.34,3))
返回1-另外:传递少于3个数字会导致错误。我在序列中得到
错误。默认值(2,长度(信息),2):wro
decimalplaces <- function(x) {
    if (abs(x - round(x)) > .Machine$double.eps^0.5) {
        nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed = TRUE)[[1]][[2]])
    } else {
        return(0)
    }
}
NUMBER / NUMBER OF DECIMAL DIGITS AS PRODUCED BY THE CODE ABOVE
[1] "0.0000437 7"
[1] "0.000195 6"
[1] "0.00025 20"
[1] "0.000193 6"
[1] "0.000115 6"
[1] "0.00012501 8"
[1] "0.00012701 20"
if (abs(x*10^8 - floor(as.numeric(as.character(x*10^8)))) > .Machine$double.eps*10^8) 
   {
   print("The number has more than 8 decimal digits")
   }
countdecimals <- function(x) 
{
  n <- 0
  while (!isTRUE(all.equal(floor(x),x)) & n <= 1e6) { x <- x*10; n <- n+1 }
  return (n)
}
decimalplaces_vec <- function(x) {

  vector <- c()
  for (i in 1:length(x)){

    if(!is.na(as.numeric(x[i]))){

      if ((as.numeric(x[i]) %% 1) != 0) {
        vector <- c(vector, nchar(strsplit(sub('0+$', '', as.character(x[i])), ".", fixed=TRUE)[[1]][[2]]))


      }else{
        vector <- c(vector, 0)
      }
    }else{
      vector <- c(vector, NA)
    }
  }
  return(max(vector))
}
count_decimals = function(x) {
  #length zero input
  if (length(x) == 0) return(numeric())

  #count decimals
  x_nchr = x %>% abs() %>% as.character() %>% nchar() %>% as.numeric()
  x_int = floor(x) %>% abs() %>% nchar()
  x_nchr = x_nchr - 1 - x_int
  x_nchr[x_nchr < 0] = 0

  x_nchr
}
> #tests
> c(1, 1.1, 1.12, 1.123, 1.1234, 1.1, 1.10, 1.100, 1.1000) %>% count_decimals()
[1] 0 1 2 3 4 1 1 1 1
> c(1.1, 12.1, 123.1, 1234.1, 1234.12, 1234.123, 1234.1234) %>% count_decimals()
[1] 1 1 1 1 2 3 4
> seq(0, 1000, by = 100) %>% count_decimals()
 [1] 0 0 0 0 0 0 0 0 0 0 0
> c(100.1234, -100.1234) %>% count_decimals()
[1] 4 4
> c() %>% count_decimals()
numeric(0)
decimalplaces <- function(x) {
  ifelse(abs(x - round(x)) > .Machine$double.eps^0.5,
         nchar(sub('^\\d+\\.', '', sub('0+$', '', as.character(x)))),
         0)
}

decimalplaces(c(234.1, 3.7500, 1.345, 3e-15))
#> 1 2 3 0
countDecimalPlaces <- function(x) {
  if ((x %% 1) != 0) {
    strs <- strsplit(as.character(format(x, scientific = F)), "\\.")
    n <- nchar(strs[[1]][2])
  } else {
    n <- 0
  }
  return(n) 
}

# example to prove the function with some values
xs <- c(1000.0, 100.0, 10.0, 1.0, 0, 0.1, 0.01, 0.001, 0.0001)
sapply(xs, FUN = countDecimalPlaces)