Изначально я разработал модель для работы с df как df1_ref. Теперь я нашел больше данных, которые мне нужны, в другом формате, например df2.
df1_ref:
id country point_id lon lat value_A
10195 United States 0 -98.52838821 35.33514183 22
10195 United States 1 -98.52838821 35.33514183 22
10195 United States 2 -98.52838821 35.33514183 22
10195 United States 3 -98.6100762 35.34134382 22
557 United States 0 -98.6100762 35.34134382 33
557 United States 1 -98.68102873 35.32256443 33
557 United States 2 -98.68102873 35.32256443 33
11354 United States 0 -95.4872305 31.85227725 22
11354 United States 1 -95.4872305 31.85227725 22
11354 United States 2 -95.474907 31.90126317 22
10131 United States 0 -98.7424264 35.777792 25
10131 United States 1 -98.58307728 35.74085314 25
10131 United States 2 -98.58307728 35.74085314 25
df2:
id country point_id_0 mid_points last_point_n route_id value_B
[10195, 557, 10123, 10105] United States [35.31514548, -98.46788543] [[35.33514183, -98.52838821], [35.34134382, -98.6100762]] [35.50457366645043, -98.98023683317503] 883 3500.69
[10029, 10027, 11354, 11355] United States [31.77540736, -95.11453227] [[31.83779617, -95.1591275], [31.89157317, -95.20337925]] [31.3187429993161, -95.450949000766] 1156 105.9092
[10131, 10204, 553, 2855] United States [35.77292283, -98.69682372] [[35.777792, -98.7424264], [35.74085314, -98.58307728]] [35.7434880000976, -99.2341759999093] 1186 4478.04
dput(df2[1:3,])
structure(list(id = c("[10195, 557, 10123, 10105, 10088, 10083]",
"[5349, 5369, 5414, 5455]", "[13184, 13217, 13235, 13251]"),
country = c("United States", "United States", "United States"
), point_id_0 = c("[35.31514548, -98.46788543]", "[40.7595028, -80.78622874]",
"[26.8019707, -99.18425714]"), mid_points = c("[[35.33514183, -98.52838821], [35.34134382, -98.6100762], [35.32256443, -98.68102873], [35.314511, -98.74060343], [35.298251, -98.796368], [35.30914456, -98.87914044], [35.40467971, -98.97597341], [35.50457367, -98.98023683]]",
"[[40.803904, -80.757632], [40.835328, -80.761536], [40.832602, -80.728872], [40.824192, -80.628096], [40.844928, -80.588928], [40.870912, -80.51968], [40.887313, -80.441874], [40.911872, -80.325376], [40.935712, -80.146112]]",
"[[26.77083569, -99.16190154], [26.8606385, -99.0916255], [26.99262, -99.04733833], [27.04302367, -99.0116915], [27.24608845, -98.94356648]]"
), last_point_n = c("[35.50457366645043, -98.98023683317503]",
"[40.9265919994913, -79.9925760003392]", "[27.24608845465542, -98.94356647741596]"
), route_id = c(883, 884, 885), value_B = c(3500.69, 20911.7359999998,
1794.77)), row.names = c(NA, -3L), class = c("tbl_df", "tbl",
"data.frame"))
Мне нужно преобразовать df2 в df1_ref, чтобы запустить предыдущую модель.
Здесь я объясняю, что мне нужно:
Различные идентификаторы в df2 входят в одно и то же наблюдение, например, [10195, 557, 10123, 10105...]; Для примера я упрощаю до 4 идентификаторов. Итак, мне нужно разделить его на строки. Я делюсь некоторыми примерами того, как это будет выглядеть в df1.
point_id_0 из df2 — это широта и долгота point_id = 0 из df1. Итак, мне нужно разделить point_id_0 на столбцы широты и долготы соответственно.
Mid_points из df2 — это следующие координаты широты/участка моей сети, каждая пара координат принадлежит одному идентификатору в том же порядке (1,2,3...). Итак, сначала Mid_points в Route_id имеет идентификатор = 557, а затем в Point_id становится 1.
Last_point_n — последняя координата, принадлежащая последнему идентификатору, например, 10105; point_id = 3.
Таким образом, df3 создается на основе df2, рассматривая df1 как эталон. Итак, окончательный df3 выглядит как df1 + value_B +route_id.
Я попробовал следующее, и это работает:
df3 <- cbind(df2,
do.call(rbind,
lapply(df2$point_id_0, jsonlite::fromJSON)))
Однако это не сработало для точек Mid_points, поскольку потребовалось бы сначала преобразовать все [широта, долгота] в строки, а затем разбить их на столбцы.
Не могли бы вы отредактировать свой вопрос и включить воспроизводимый образец из вашего реального df2
, чтобы у нас было четкое представление о структуре, с которой вы работаете, и было что протестировать? Выход из dput(df2[1:3,])
был бы идеальным.
Я добавил dput(df2[1:3,]), как предложил @margusl.
Сосредоточившись только на 1-й строке варианта dput вашего df2
, есть 6 значений id
([10195, 557, 10123, 10105, 10088, 10083]
), но 8 mid_points
+ 2 дополнительных точки (point_id_0
, last_point_n
), каково ожидаемое количество результирующих строк только для этой единственной входной строки? 60 как 6 * (8+2)? Или должно быть как-то 6? В вашем первом примере количество df2
удобно совмещается с количеством пар координат для каждой строки (4 значения id
и координаты 2+1+1), в примере dput это больше не применяется. Является ли исходный источник данных JSON/GeoJSON?
Да, я только что обнаружил, что [[широта, долгота], [широта, долгота] и т. д. — это формат JSON. Итак, я применил это для point_id_0 (у которого есть только одна пара широты и долготы), и это работает: df3 <- cbind(df2, do.call(rbind, lapply(df2$point_id_0, jsonlite::fromJSON)))
. Однако это не сработало для точек Mid_points, поскольку потребовалось бы сначала преобразовать все [широта, долгота] в строки, а затем разбить их на столбцы.
@dmoyaec, пожалуйста, попытайтесь найти ответ на первую часть моего предыдущего комментария - каков ожидаемый результат в случаях, когда количество id
не совпадает с общим количеством координат. Для всех 3 строк вашего образца dput у вас меньше id
, чем mid_points
, (6, 4, 4)
против (8, 9, 5)
, i.sstatic.net/yR65ms0w.png
@margusl, я проверил. В целом row count = point_id_0 + mid_points + last_point_n
. point_id_0
и last_point_n
имеют уникальные id
, однако mid_points
может иметь несколько id
, как видно из df1
(например, 10195 имеет 4 долготы/широты, 557 имеет 3...). Это усложняет задачу, поскольку нам нужно сопоставить mid_points
из df2
с id
из df1
.
Похоже, это делает работу для mid_points
: json_coordinates <- field_TO_pro_simplify %>% select(mid_points ) json_coordinates <- toJSON(json_coordinates)
# Анализ строки JSON parsed_json <- fromJSON(json_coordinates)
# Извлечение координат coordinates_list <- lapply(parsed_json$mid_points , function(x) { fromJSON(x) })
# Сведение списка координат и преобразование в фрейм данных coordinates_df <- do.call(rbind, lapply(coordinates_list, function(x) { data.frame(Coordinates = paste0("[", x[,1], ", ", x[,2], "]")) }))
Это частичный ответ, показывающий, как можно работать со столбцами, содержащими строки JSON (вложенных) списков, и с результирующими столбцами списка. Боюсь, в вопросе недостаточно информации, чтобы присвоить значения id
и point_id
координатам средней точки.
Результатом id
является столбец списка, для первой и последней точек каждой группы id
список содержит одно значение; для всех средних точек он содержит оставшиеся значения идентификаторов.
library(dplyr, warn.conflicts = FALSE)
library(tidyr)
library(purrr)
library(jsonlite, warn.conflicts = FALSE)
df2 |>
# parse JSON columns with parse_json
mutate(across(c(id, point_id_0:last_point_n), \(x) map(x, parse_json))) |>
# combine point_id_0, mid_points & last_point_n into a single column, rowwise
rowwise() |>
mutate(pts = c(list(point_id_0), mid_points, list(last_point_n)) |> list(),
.keep = "unused", .after = country) |>
ungroup() |>
# unnest newly create pts column, hoist lon & lat to top-level columns
unnest_longer(pts) |>
hoist(pts, lon = 2, lat = 1) |>
select(-pts) |>
# group by id, assign 1st and last id-s, for mid-points leave a list of id candidates
mutate(
id = case_when(row_number() == 1 ~ list(first(id[[1]])),
row_number() == n() ~ list(last (id[[1]])),
.default = id[[1]] |> head(-1) |> tail(-1) |> list()) ,
.by = id) |>
# display list column content and increase number of displayed digits
rowwise() |>
mutate(id_chr = paste0(id, collapse = ","), .after = id, across(lon:lat, \(x) tibble::num(x, digits = 9) )) |>
ungroup() |>
print(n = 28)
Результат:
#> # A tibble: 28 × 7
#> id id_chr country lon lat route_id value_B
#> <list> <chr> <chr> <num:.9!> <num:.9!> <dbl> <dbl>
#> 1 <int [1]> 10195 United… -98.467885430 35.315145480 883 3501.
#> 2 <list [4]> 557,10123,101… United… -98.528388210 35.335141830 883 3501.
#> 3 <list [4]> 557,10123,101… United… -98.610076200 35.341343820 883 3501.
#> 4 <list [4]> 557,10123,101… United… -98.681028730 35.322564430 883 3501.
#> 5 <list [4]> 557,10123,101… United… -98.740603430 35.314511000 883 3501.
#> 6 <list [4]> 557,10123,101… United… -98.796368000 35.298251000 883 3501.
#> 7 <list [4]> 557,10123,101… United… -98.879140440 35.309144560 883 3501.
#> 8 <list [4]> 557,10123,101… United… -98.975973410 35.404679710 883 3501.
#> 9 <list [4]> 557,10123,101… United… -98.980236830 35.504573670 883 3501.
#> 10 <int [1]> 10083 United… -98.980236833 35.504573666 883 3501.
#> 11 <int [1]> 5349 United… -80.786228740 40.759502800 884 20912.
#> 12 <list [2]> 5369,5414 United… -80.757632000 40.803904000 884 20912.
#> 13 <list [2]> 5369,5414 United… -80.761536000 40.835328000 884 20912.
#> 14 <list [2]> 5369,5414 United… -80.728872000 40.832602000 884 20912.
#> 15 <list [2]> 5369,5414 United… -80.628096000 40.824192000 884 20912.
#> 16 <list [2]> 5369,5414 United… -80.588928000 40.844928000 884 20912.
#> 17 <list [2]> 5369,5414 United… -80.519680000 40.870912000 884 20912.
#> 18 <list [2]> 5369,5414 United… -80.441874000 40.887313000 884 20912.
#> 19 <list [2]> 5369,5414 United… -80.325376000 40.911872000 884 20912.
#> 20 <list [2]> 5369,5414 United… -80.146112000 40.935712000 884 20912.
#> 21 <int [1]> 5455 United… -79.992576000 40.926591999 884 20912.
#> 22 <int [1]> 13184 United… -99.184257140 26.801970700 885 1795.
#> 23 <list [2]> 13217,13235 United… -99.161901540 26.770835690 885 1795.
#> 24 <list [2]> 13217,13235 United… -99.091625500 26.860638500 885 1795.
#> 25 <list [2]> 13217,13235 United… -99.047338330 26.992620000 885 1795.
#> 26 <list [2]> 13217,13235 United… -99.011691500 27.043023670 885 1795.
#> 27 <list [2]> 13217,13235 United… -98.943566480 27.246088450 885 1795.
#> 28 <int [1]> 13251 United… -98.943566477 27.246088455 885 1795.
Входной кадр:
df2 <- structure(list(id = c("[10195, 557, 10123, 10105, 10088, 10083]",
"[5349, 5369, 5414, 5455]", "[13184, 13217, 13235, 13251]"),
country = c("United States", "United States", "United States"
), point_id_0 = c("[35.31514548, -98.46788543]", "[40.7595028, -80.78622874]",
"[26.8019707, -99.18425714]"), mid_points = c("[[35.33514183, -98.52838821], [35.34134382, -98.6100762], [35.32256443, -98.68102873], [35.314511, -98.74060343], [35.298251, -98.796368], [35.30914456, -98.87914044], [35.40467971, -98.97597341], [35.50457367, -98.98023683]]",
"[[40.803904, -80.757632], [40.835328, -80.761536], [40.832602, -80.728872], [40.824192, -80.628096], [40.844928, -80.588928], [40.870912, -80.51968], [40.887313, -80.441874], [40.911872, -80.325376], [40.935712, -80.146112]]",
"[[26.77083569, -99.16190154], [26.8606385, -99.0916255], [26.99262, -99.04733833], [27.04302367, -99.0116915], [27.24608845, -98.94356648]]"
), last_point_n = c("[35.50457366645043, -98.98023683317503]",
"[40.9265919994913, -79.9925760003392]", "[27.24608845465542, -98.94356647741596]"
), route_id = c(883, 884, 885), value_B = c(3500.69, 20911.7359999998,
1794.77)), row.names = c(NA, -3L), class = c("tbl_df", "tbl",
"data.frame"))
df2
#> # A tibble: 3 × 7
#> id country point_id_0 mid_points last_point_n route_id value_B
#> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl>
#> 1 [10195, 557, 1012… United… [35.31514… [[35.3351… [35.5045736… 883 3501.
#> 2 [5349, 5369, 5414… United… [40.75950… [[40.8039… [40.9265919… 884 20912.
#> 3 [13184, 13217, 13… United… [26.80197… [[26.7708… [27.2460884… 885 1795.
glimpse(df2)
#> Rows: 3
#> Columns: 7
#> $ id <chr> "[10195, 557, 10123, 10105, 10088, 10083]", "[5349, 5369,…
#> $ country <chr> "United States", "United States", "United States"
#> $ point_id_0 <chr> "[35.31514548, -98.46788543]", "[40.7595028, -80.78622874…
#> $ mid_points <chr> "[[35.33514183, -98.52838821], [35.34134382, -98.6100762]…
#> $ last_point_n <chr> "[35.50457366645043, -98.98023683317503]", "[40.926591999…
#> $ route_id <dbl> 883, 884, 885
#> $ value_B <dbl> 3500.69, 20911.74, 1794.77
Также обратите внимание, что все 28 пар координат в предоставленном (dput) образце уникальны, и есть признаки проблем с точностью. Например, рассмотрим строки 9 и 10 результирующего кадра. Соответствующие значения входных данных:
35.50457367, -98.98023683
35.50457366645043, -98.98023683317503
У меня нет времени, чтобы сформулировать полный ответ, но взгляните на
separate_longer_delim()
из пакетаtidyr
. Это должно решить ваше дело. И подумайте о том, чтобы выполнить преобразованиеdf2
более чем за один шаг.