Подтвердить что ты не робот

Упрощение POSIX node с помощью RJSONIO:: fromJSON()

У меня есть следующий вектор двойных значений x, где каждый элемент представляет собой дату POSIX

x <- c(1417621083, 1417621204, 1417621384, 1417621564, 1417621623)

Я использую пакет RJSONIO и хотел бы продолжать это делать.

Как упражнение, я хотел бы преобразовать эти значения в текст JSON, а затем снова прочитать их снова в R, но у меня возникли проблемы с получением представлений даты и времени в хороший упрощенный результат списка. В JSON даты должны быть в специальном формате, поэтому значения в x преобразуются в следующее:

dates <- c("/new Date(1417621083)", "/Date(1417621204)", "/Date(1417621384)", 
           "/Date(1417621564)", "/Date(1417621623)")

Когда я запускаю dates со вторым произвольным вектором через парсер RJSONIO, все кажется плавным.

library(RJSONIO)
make <- toJSON(list(date = dates, value = LETTERS))

Затем, когда я анализирую новый текст JSON, используя параметр stringFun с помощью процедуры R-json C для дат, результатом является список из двух элементов, первый элемент - список, а второй - атомный вектор.

(read <- fromJSON(make, stringFun = "R_json_dateStringOp"))
# $date
# $date[[1]]
# [1] "2014-12-03 07:38:03 PST"
# 
# $date[[2]]
# [1] "2014-12-03 07:40:04 PST"
# 
# $date[[3]]
# [1] "2014-12-03 07:43:04 PST"
# 
# $date[[4]]
# [1] "2014-12-03 07:46:04 PST"
# 
# $date[[5]]
# [1] "2014-12-03 07:47:03 PST"
# 
# 
# $value
# [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
# [14] "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

Но я ожидал список из двух векторов, и я предпочел бы его в виде

# $date
# [1] "2014-12-03 07:38:03 PST" "2014-12-03 07:40:04 PST"
# [3] "2014-12-03 07:43:04 PST" "2014-12-03 07:46:04 PST"
# [5] "2014-12-03 07:47:03 PST"
# 
# $value
# [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q"
# [18] "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

Я попробовал несколько способов упростить результат из вызова fromJSON(), и ни одна из них не сработала. Вот несколько моих попыток:

Использование обработчика: Это упрощает результат, но не позволяет переформатировать даты

h1 <- basicJSONHandler(simplify = TRUE)
fromJSON(make, handler = h1, stringFun = "R_json_dateStringOp")
# $date
# [1] "/new Date(1417621083)" "/Date(1417621204)"    
# [3] "/Date(1417621384)"     "/Date(1417621564)"    
# [5] "/Date(1417621623)"    
# 
# $value
# [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
# [14] "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

Попытка аргумента simplify : Я пробовал несколько разных вариантов этого, и никто не работал.

fromJSON(make, simplify = StrictCharacter)
# $date
# [1] "/new Date(1417621083)" "/Date(1417621204)"    
# [3] "/Date(1417621384)"     "/Date(1417621564)"    
# [5] "/Date(1417621623)"    
#
# $value
#  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
# [14] "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

Есть ли способ упростить результат для дат в вызове fromJSON()?

4b9b3361

Ответ 1

Я думаю, что вы не можете получить принуждение дат и их упрощение к вектору в одно и то же время. По той простой причине, что это еще не реализовано в RJSONIO. В самом деле, как вы упомянули, упрощение выполняется с использованием одного флага: StrictLogical, StrictNumeric и StrictCharacter, которые создают логические, числовые или символьные векторы. Возможно, вам следует связаться с сопровождающим, чтобы добавить флаг StrictPosixct для дат POSIXct.

Использование stringFun не может помочь, поскольку оно получает скалярный элемент (символьную строку) и не знает других векторных элементов. Вы можете проверить это, определив функцию R как параметр stringFun и поместите в нее браузер.

convertJSONDate <-
  function(x)
  {
     if(grepl('Date',x)){
       val <- sub('.*[(]([0-9]+).*','\\1',x)
       return(structure(as.numeric(val)/1000, class = c("POSIXct", "POSIXt")))
     }
     x
   }

Я думаю, вы хотите сделать принуждение/упрощение, когда вы разбираете свой json по причине производительности. Я бы использовал другую стратегию:

  • Я принуждаю свои числовые значения к POSIXct, и я буду хранить их как символ в хорошо отформатированных датах. Это лучше, чем специальный (уродливый) формат даты "Дата (.., дата" ) RJSONIO. Помните, что формат json - это стандартный формат, который может быть проанализирован другими языками (python, js,..)
  • Затем проанализируйте мои даты как обычный символ, и я использую быстрый пакет fasttime, чтобы принудить его к вектору POSIXct.

вот какой код, чтобы показать это:

## coerce x to dates a well formatted dates
dd <- as.character(as.POSIXct(x,origin = '1970-01-01' , tz = "UTC"))
## read it again in a fast way
fastPOSIXct(fromJSON(make)$date)

[1] "2014-12-03 16:38:03 CET" "2014-12-03 16:40:04 CET" "2014-12-03 16:43:04 CET" "2014-12-03 16:46:04 CET" "2014-12-03 16:47:03 CET"

Ответ 2

Из значения read, которое я предполагаю, является желаемой отправной точкой... это один из способов:

> dd <- sapply(read, c) 
> class(dd) <- "POSIXct"
> dd
[1] "2014-12-03 07:38:03 PST" "2014-12-03 07:40:04 PST" "2014-12-03 07:43:04 PST"
[4] "2014-12-03 07:46:04 PST" "2014-12-03 07:47:03 PST"

Класс-принуждение является "грязным", но я уже пробовал немало других (неудачных) стратегий, например. unlist, sapply( read,"[[",1), sapply(read, c)), для сохранения атрибутов, поэтому я решил спуститься в грязь с R и размахивать классом-молотом.

Ответ 3

Поскольку срок действия ресурса истек, и выясняется, что в настоящее время это невозможно сделать в RJSONIO (или так кажется), я собираюсь использовать это как альтернативный метод, если другие пользователи столкнутся с этой проблемой и нужно решение.

Пакет jsonlite может легко выполнить эту операцию. Все, что нам нужно сделать, это добавить класс POSIXt к числовому вектору и указать "mongo" для синтаксического анализатора в неэкспортируемой функции asJSON.

# unloadNamespace(RJSONIO)  ## to avoid confusion between packages
library(jsonlite)    

x <- c(1417621083, 1417621204, 1417621384, 1417621564, 1417621623)

class(x) <- "POSIXt"    

data <- list(dates = x, values = letters[1:5])

json <- jsonlite:::asJSON(data, POSIXt = "mongo")

fromJSON(json)
# $dates
# [1] "2014-12-03 07:38:03 PST" "2014-12-03 07:40:04 PST"
# [3] "2014-12-03 07:43:04 PST" "2014-12-03 07:46:04 PST"
# [5] "2014-12-03 07:47:03 PST"
# 
# $values
# [1] "a" "b" "c" "d" "e"