как вернуть число десятичных знаков в 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 ненулевых десятичных значений.
- Как преобразовать таблицу в кадр данных
- Как определить, есть ли у вас интернет-соединение в R
- Есть ли способ `source ()` и продолжить после ошибки?
- Подавить вывод одной команды в R
- Ошибка: использование стека C слишком близко к пределу
- Функция очистки консоли в R и RStudio
- Преобразовать значения в столбце в имена строк в существующем кадре данных в R
- Проверить наличие директории и создать, если не существует
- как получить значение, когда имя переменной передается как строка
- Почему я получаю «предупреждение, что длинная длина объекта не кратная короткой длине объекта»?
- Удалите повторяющиеся пары столбцов, сортируйте строки на основе двух столбцов
- poly () в lm (): разница между исходным и ортогональным
- Найти ближайшее значение в векторе с бинарным поиском
Вы можете легко написать небольшую функцию для задачи, например:
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))))));