我在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和AniLac 5的脚本,因为这些坐标没有以足够的精度记录。我想丢弃经度和纬度都小于3的非零小数值的坐标。
答案 0 :(得分:24)
您可以轻松地为任务编写一个小函数,例如:
decimalplaces <- function(x) {
if ((x %% 1) != 0) {
nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed=TRUE)[[1]][[2]])
} else {
return(0)
}
}
并运行:
> decimalplaces(23.43234525)
[1] 8
> decimalplaces(334.3410000000000000)
[1] 3
> decimalplaces(2.000)
[1] 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)
}
}
答案 1 :(得分:9)
这是一种方法。它会检查小数点后的前20个位置,但如果您有其他想法,可以调整数字20。
x <- pi
match(TRUE, round(x, 1:20) == x)
这是另一种方式。
nchar(strsplit(as.character(x), "\\.")[[1]][2])
答案 2 :(得分:9)
罗马的建议:
num.decimals <- function(x) {
stopifnot(class(x)=="numeric")
x <- sub("0+$","",x)
x <- sub("^.+[.]","",x)
nchar(x)
}
x <- "5.2300000"
num.decimals(x)
如果您的数据不能保证格式正确,您应该进行更多检查以确保其他角色不会偷偷摸摸。
答案 3 :(得分:2)
我已经测试了一些解决方案,我发现该解决方案对其他报告的错误很健壮。
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)
答案 4 :(得分:1)
在[R]中,2.30000和2.3之间没有区别,两者都被舍入到2.3,因此如果你想要检查,那么一个并不比另一个更精确。另一方面,如果这不是你的意思:如果你真的想这样做,你可以使用1)乘以10,2)使用floor()函数3)除以10 4)检查与原始的相等。 (但请注意,将浮点数比较为平等是不好的做法,请确保这确实是您想要的)
答案 5 :(得分:1)
对于常见的应用程序,这里修改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)
}
}
通常,浮点数如何存储为二进制可能存在问题。试试这个:
> sprintf("%1.128f", 0.00000000001)
[1] "0.00000000000999999999999999939458150688409432405023835599422454833984375000000000000000000000000000000000000000000000000000000000"
我们现在有多少小数?
答案 6 :(得分:1)
不要劫持线程,只是将其发布在此处,因为它可能有助于某人处理我尝试使用建议的代码完成的任务。
不幸的是,即使the updated @ 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)
}
}
在我的案例中产生了以下结果
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")
}
PS:我可能会遗漏一些与.Machine$double.eps
没有关系的内容,所以请小心
答案 7 :(得分:1)
另一个贡献,完全保留为数字表示形式,而无需转换为字符:
countdecimals <- function(x)
{
n <- 0
while (!isTRUE(all.equal(floor(x),x)) & n <= 1e6) { x <- x*10; n <- n+1 }
return (n)
}
答案 8 :(得分:1)
如果此处有人需要上述GergelyDaróczi提供的功能的矢量化版本:
Mon Nov 11 2019 00:00:00 GMT+0400 (Armenia Standard Time)
答案 9 :(得分: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)]
}
以下是strsplit()
版本。
nd2 <- function(xx,trailingonly=F,...) if(length(xx)>1) {
fn<-sys.function();
return(sapply(xx,fn,trailingonly=trailingonly))
} else {
sum(c(nchar(strsplit(as.character(abs(xx)),'\\.')[[1]][ifelse(trailingonly, 2, T)]),0),na.rm=T);
}
字符串版本以15位数字切断(实际上,不确定为什么另一个地方的论点被一个人关闭......它超越的原因是它计算了两个方向的数字如果数量足够大,它可以达到两倍大小)。 as.character()
可能有一些格式化选项可以nd2()
为places
nd1()
nd1(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0));
# 2 2 1 3 1 4 16 17 1
nd2(c(1.1,-8.5,-5,145,5,10.15,pi,44532456.345243627,0));
# 2 2 1 3 1 4 15 15 1
参数提供等效选项。
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))))));
更快。
#Ingredients per 48 cookies
sugar = 1.5
butter = 1
flour = 2.75
#what percent of 48 are the ingredients
sugar1 = (1.5/48)
butter1 = (1/48)
flour1 = (2.75/48)
#ask for amount of cookies from user
cookies = int (input('How many cookies would you like to bake? '))
#calculate ingredient amounts
sugar2 = (sugar1 * cookies)
format(sugar2, '.2f')
butter2 = (butter1 * cookies)
format(butter2, '.2f')
flour2 = (flour1 * cookies)
format(flour2, '.2f')
print ('To make', cookies, ' you need', sugar2, 'cups of sugar,',
butter2, 'cups of butter, and', flour2, ' cups of flour.')
答案 10 :(得分:0)
基于daroczig函数的矢量解决方案(还可以处理包含字符串和数字的脏列):
chains =1
答案 11 :(得分:0)
不确定上面为什么不使用这种简单方法(从 tidyverse / magrittr 加载管道)。
count_decimals = function(x) {
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
}
> #test
> 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
因此,R似乎没有内部区分最初获得1.000
和1
的区别。因此,如果一个人的矢量输入包含各种十进制数字,则可以通过取小数位数的最大值来查看(至少)最初具有多少个数字。
编辑:已修复的错误