validate - regular expression json schema
Cómo descomprimir la columna de tipo JSON anidada en un marco de datos con R(más el problema RegEx) (1)
Desempacar JSON puede ser una tarea ardua, especialmente si está profundamente anidado. La mayoría de los paquetes de lectura JSON ( jsonlite
, RJSONIO
, etc.) pueden convertir datos en algo cercano a un data.frame, pero arreglar la estructura requiere un entendimiento que las funciones del lector no tienen. Dado que JSON se corresponde casi por completo con las listas de R, la limpieza de los datos provenientes de JSON generalmente implica una gran cantidad de lapply
y sus variantes. Aquí purrr
, que tiene muchas variantes útiles y funciones de ayuda y funciona perfectamente con dplyr
.
library(tidyverse)
# Read data
json <- jsonlite::stream_in(file(''~/Downloads/jsondata.json''))
# Initial cleanup to proper data.frame
json <- json$payload %>% map_df(simplify_all) %>% dmap(simplify) %>%
mutate(uuid = json$uuid, # re-add uuid subset out at beginning
# Convert hours to a list column of data.frames
hours = hours %>% map_if(negate(is.na), jsonlite::fromJSON) %>%
map(~map_df(.x, as_data_frame, .id = ''day'')),
# Add Boolean variable for whether Sunday opening hours are before 10a. Subset,
open_sun_before_10 = hours %>% map(~.x %>% filter(day == ''sunday'') %>% .[[2]]) %>%
map(as.POSIXct, format = ''%H:%M'') %>% # convert to datetime,
map(~.x < as.POSIXct(''10:00'', format = ''%H:%M'')) %>% # compare to 10a
map_lgl(~ifelse(length(.x) == 0, NA, .x))) # and cleanup.
Mientras que stream_in
devolvió un data.frame con dos columnas (una muy anidada profundamente), las columnas ahora están menos anidadas. Sin embargo, todavía hay estructuras JSON en algunas de las columnas intactas, que deberán abordarse si desea utilizar los datos.
json
#> # A tibble: 538 × 42
#> existence_full geo_virtual latitude
#> <dbl> <chr> <chr>
#> 1 1.000000 ["56.9459720|-2.1971226|20|within_50m|4"] 56.945972
#> 2 1.000000 ["56.237480|-5.073578|20|within_50m|4"] 56.237480
#> 3 1.000000 ["51.483872|-0.606820|100|rooftop|2"] 51.483872
#> 4 1.000000 ["57.343233|-2.191955|100|rooftop|4"] 57.343233
#> 5 1.000000 ["53.225815|-4.094775|20|within_50m|4"] 53.225815
#> 6 1.000000 ["58.9965740|-3.1882195|20|within_50m|4"] 58.996574
#> 7 1.000000 ["57.661419|-2.520144|100|rooftop|4"] 57.661419
#> 8 1.000000 ["51.642727|-3.934845|20|within_50m|4"] 51.642727
#> 9 0.908251 <NA> <NA>
#> 10 1.000000 ["56.510558|-5.401638|100|rooftop|2"] 56.510558
#> # ... with 528 more rows, and 39 more variables: locality <chr>,
#> # `_records_touched` <chr>, address <chr>, email <chr>,
#> # existence_ml <dbl>, domain_aggregate <chr>, name <chr>,
#> # search_tags <list>, admin_region <chr>, existence <dbl>,
#> # category_labels <list>, post_town <chr>, region <chr>,
#> # review_count <chr>, geocode_level <chr>, tel <chr>, placerank <int>,
#> # longitude <chr>, placerank_ml <dbl>, fax <chr>,
#> # category_ids_text_search <chr>, website <chr>, status <chr>,
#> # geocode_confidence <chr>, postcode <chr>, category_ids <list>,
#> # country <chr>, `_geocode_quality` <chr>, hours_display <chr>,
#> # hours <list>, neighborhood <list>, languages <chr>,
#> # address_extended <chr>, status_closed <chr>, po_box <chr>,
#> # name_variants <list>, yext_id <chr>, uuid <chr>,
#> # open_sun_before_10 <lgl>
Y las columnas creadas:
json %>% select(hours, open_sun_before_10)
#> # A tibble: 538 × 2
#> hours open_sun_before_10
#> <list> <lgl>
#> 1 <tibble [1 × 2]> NA
#> 2 <tibble [1 × 2]> NA
#> 3 <tibble [7 × 3]> FALSE
#> 4 <tibble [1 × 2]> NA
#> 5 <tibble [7 × 3]> FALSE
#> 6 <tibble [1 × 2]> NA
#> 7 <tibble [1 × 2]> NA
#> 8 <tibble [6 × 3]> NA
#> 9 <tibble [1 × 2]> NA
#> 10 <tibble [7 × 3]> TRUE
#> # ... with 528 more rows
Soy muy nuevo en R, y actualmente estoy atascado en este problema: así que importé un archivo JSON y ya *** lo convertí a un marco de datos ***, ahora necesito devolver las filas en condición:
Como puede ver en la imagen, tengo una columna de horas de grabación (horas de carga). Mi META es para conocer las horas que se reúnen: 1. domingo 2. hora antes de las 10AM.
Lo intenté de varias maneras, pero de alguna manera ni siquiera se acerca ... No he tratado con esa forma anidada antes ... así que tengo que buscar tu idea y ayuda ...
por ejemplo, un elemento en la columna de carga útil.hours
payload.hours ...
[530] "{/" lunes / ": [[/" 10:30 / ", /" 16:00 / "]], /" martes / ": [[/" 10:30 / ", /" 16 : 00 / "]], /" miércoles / ": [[/" 10:30 / ", /" 16:00 / "]], /" jueves / ": [[/" 10:30 / ", / "16:00 /"]], / "viernes /": [[/ "10:30 /", / "16:00 /"]], / "sábado /": [[/ "10: 30 /" , / "16:00 /"]], / "sunday /": [[/ "10:30 /", / "16: 00 /"]]} "
esto es lo que utilicé para desempaquetar las listas anidadas en la columna de "horas" ... pero no funciona ...
library(ndjson)
json<- ndjson::stream_in("#localpath")
#successfully converted json to a dataframe...but each element in payload.hours column remains nested like above.
lapply(json$payload.hours, jsonlite::fromJSON)
#continue unwarp nested jason column BUT RESULT Error in if (is.character(txt) && length(txt) == 1 && nchar(txt, type = "bytes") < :missing value where TRUE/FALSE needed
Otro enfoque que probé (PARA MUCHO TIEMPO) es RegEx
hrs<-json1$payload.hours #select column hours into hrs
tme<-"sunday{1}.{8}[0-9]{1}/"" # ???(not sure about this...seruously)...? match string with sunday and after 8characters..aka find preceding digit{1} when meet ":"
iftme<-grepl(tme,hrs) #set logical factor T/F if matches
checkhrs<-hrs[iftme] #check if open hours are correct
checkhrs
Y esto parece funcionar ... pero no estoy seguro de por qué ... (SÍ. ID. POR QUÉ) ... así que si alguien pudiera explicarme, ¡sería genial!
Este es el archivo json original:
https://drive.google.com/open?id=0B-jU6pp4pjS4Smg2RGpHSTlvN2c
Esta es la salida de RegEx ... parece correcto ... pero no estoy seguro de mi expresión ... LOL