как вернуть число десятичных знаков в R

Я работаю в R. У меня есть ряд координат в десятичных gradleусах, и я хотел бы отсортировать эти координаты на сколько десятичных знаков эти числа (т.е. я хочу сбросить координаты, у которых слишком мало десятичных знаков).
Есть ли функция в 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 ненулевых десятичных значений.

Вы можете легко написать небольшую функцию для задачи, например:

 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 

Обновление (3 апреля 2018 года) для отчета @ 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) } } 

Радуясь предложению Романа:

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

Если ваши данные не гарантированы надлежащей формы, вы должны сделать больше проверок, чтобы другие символы не подкрались.

Вот один из способов. Он проверяет первые 20 мест после десятичной точки, но вы можете настроить число 20, если у вас есть что-то еще в виду.

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

Вот еще один способ.

 nchar(strsplit(as.character(x), "\\.")[[1]][2]) 

В [R] нет разницы между 2.30000 и 2.3, оба округляются до 2.3, поэтому одно не более точное, чем другое, если это то, что вы хотите проверить. С другой стороны, если это не то, что вы имели в виду: если вы действительно хотите это сделать, вы можете использовать 1) умножить на 10, 2) использовать функцию floor () 3) делить на 10 4) проверить равенство с оригиналом. (Однако имейте в виду, что сравнение поплавков для равенства – это плохая практика, убедитесь, что это действительно то, что вы хотите)

Для общего применения здесь приведена модификация кода 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" 

Сколько у нас десятичных знаков?

Не означает, чтобы захватить stream, просто разместив его здесь, поскольку это может помочь кому-то справиться с задачей, которую я пытался выполнить с предлагаемым кодом.

К сожалению, даже обновленное решение @ 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 в связи с тем, что я не взял корень .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) } 

Интересный вопрос. Вот еще одна настройка работы вышеупомянутых респондентов, векторизация и расширение для обработки цифр слева от десятичной точки. Протестировано против отрицательных цифр, что дало бы неправильный результат для предыдущего strsplit() .

Если желательно только считать те, что trailingonly справа, аргумент 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)))))); 
  • Как мне назвать столбец имен строк в r
  • Преобразовать значения в столбце в имена строк в существующем кадре данных в R
  • Элементарно означает над списком матриц
  • Как вы конвертируете даты / время из одного часового пояса в другой в R?
  • Какой самый полезный трюк?
  • Заменить содержимое столбца факторов в R-файле
  • Какая польза от этого?
  • Альтернатива expand.grid для data.frames
  • R усиливает местный охват
  • Выберите эквивалентные строки
  • poly () в lm (): разница между исходным и ортогональным
  • Давайте будем гением компьютера.