is.numeri c и is.integer дают неожиданные результаты - PullRequest
0 голосов
/ 19 марта 2020

При запросе к моей XML -базы данных, по сути, результат получается в виде вектора с одним элементом на строку.

input <- c("[1, 1.05e0, true(), \"1\", false()]", "[2, 4.0e0, true(), \"8\", true()]" more rows)

После преобразования каждого элемента в список легко добавить каждый элемент от вектора в виде строки до кадра данных. Остается только преобразовать каждый столбец в соответствующий тип. Моя проблема в том, что я не знаю, как определить тип для каждого столбца.
Я начинаю с создания шаблона на основе первого элемента из входных данных.

> template <- input[[1]] %>% str_replace_all("[\\[\\]]", "") %>% str_replace_all(", ", ",") %>%
+   str_replace_all("\"", "'") %>% strsplit(",") %>% .[[1]]
> template
[1] "1"       "1.05e0"  "true()"  "'1'"     "false()"

Затем я использую этот шаблон для определения типа столбца.

test_type <- function(template) {
  Bools <- which(template %in% c("true", "true()", "false", "false()"))
  NonBools <- setdiff(1:length(template), Bools)
  cat("Bools", "\n")
  for (i in Bools) {
    cat(i, "\n")
  }
  cat("NonBools", "\n")
  for (i in NonBools) {
    if (is.numeric(template[[i]])) { Type <- "Num"}
    else if (is.integer(template[[i]])) {Type <- "Int"}
    else {Type <- "Char"}
    cat(i, template[i], Type, "\n", sep = " ")
  }
}

> test_type(template)
Bools 
3 
5 
NonBools 
1 1 Char 
2 1.05e0 Char 
4 '1' Char

Как видите, моя функция не возвращает тип Райта. is.numeric(template[[1]]) возвращает FALSE, но as.numeric(template[[1]]) возвращает 1. as.numeric(template[[4]]) возвращает NA

Может кто-нибудь объяснить, почему is.numeri c () возвращает неправильный ответ? Как я могу определить правильный тип?

Бен

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Мы можем исправить функцию OP, используя:

test_type <- function(template) {

  Bools <- which(template %in% c("true", "true()", "false", "false()"))
  NonBools <- setdiff(1:length(template), Bools)
  cat("Bools", "\n")
  for (i in Bools) {
    cat(i, "\n")
 }
  cat("NonBools", "\n")
  for (i in NonBools) {
     num <- as.numeric(template[i])
     if (!is.na(num) && num %% 1 != 0)  Type <- "Num"
     else if (!is.na(num) && num %% 1 == 0) Type <- "Int"
     else Type <- "Char"
     cat(i, template[i], Type, "\n", sep = " ")
   }
}


suppressWarnings(test_type(template))

#Bools 
#3 
#5 
#NonBools 
#1 1 Int 
#2 1.05e0 Num 
#4 '1' Char 

Примечания:

  • Когда мы проверяем is.numeric(template[[i]]), template[[i]] все еще символ и не изменил своего класса. Так что is.numeric всегда терпит неудачу.

  • Целые числа удовлетворяют критерию as.numeric. Проверьте class(1L) и is.numeric(1L). Поэтому нам нужны другие тесты для проверки целых чисел.

  • Мы используем здесь num %% 1 == 0 для проверки целых чисел.

0 голосов
/ 19 марта 2020

Вот как я могу это сделать, используя case_when из пакета dplyr:

template <- c("1", "1.05e0", "true()", "'1'", "false()")

dplyr::case_when(
  tolower(template) %in% c('true', 'false', 'true()', 'false()')  ~ 'Boolean',
  as.integer(template) == template ~ 'Integer',
  !is.na(as.numeric(template)) ~ 'Numeric',
  TRUE ~ 'Character')

#  "Integer"   "Numeric"   "Boolean"   "Character" "Boolean"  

Это также можно сделать с помощью операторов if/else, но я думаю, что синтаксис case_when лучше.

Я также добавил в tolower() для шаблона, чтобы убедиться, что TRUE и FALSE также считаются булевыми

Редактировать:

Целое число не работало, так что теперь сделайте это по-другому

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...