#r #list #dataframe #data.table
#r #Список #фрейм данных #данные.таблица
Вопрос:
У меня есть data.table
, что по какой-то причине имеет несколько столбцов как list
. Мне нужно найти быстрый способ преобразовать эти столбцы в обычные векторные столбцы со integer
значениями.
Смотрите воспроизводимый пример и мою попытку ниже.
reprex
dt = structure(list(fromId = c("89a901291abffff", "89a901295b7ffff",
"89a9012809bffff", "89a901285cfffff"), travel_time_p001 = c(45L,
43L, 38L, 27L), travel_time_p050 = list(54L, 52L, 44L, 35L),
travel_time_p098 = list(62L, 60L, 55L, 44L)), row.names = c(NA,
-4L), class = c("data.table", "data.frame"))
head(dt)
> fromId travel_time_p001 travel_time_p050 travel_time_p098
> 1: 89a901291abffff 45 54 62
> 2: 89a901295b7ffff 43 52 60
> 3: 89a9012809bffff 38 44 55
> 4: 89a901285cfffff 27 35 44
sapply(dt, class)
> fromId travel_time_p001 travel_time_p050 travel_time_p098
>"character" "integer" "list" "list"
class(dt$travel_time_p098[1])
> [1] "list"
Я нашел этот способ исправить один столбец, хотя я не уверен, что это можно сделать быстрее.
dt[, travel_time_p098 := Reduce(rbind, travel_time_p098)]
Теперь задача усложняется, когда я пытаюсь сделать это для нескольких столбцов. Это то, что я безуспешно пытался. Я надеюсь, что кто-нибудь сможет придумать быстрое решение, возможно, используя data.table
цикл с. set()
# identify which columns need to be transformed.
colpositions <- sapply(dt, class) == 'list'
colnms <- names(dt)[colpositions]
# failed attempt
dt[, colnms := Reduce(rbind, .SD), .SDcols = colnms]
Есть предложения?
Ответ №1:
Если list
элементы имеют ту же длину, что и количество строк, можно выполнить цикл по всем столбцам, выполнить проверку с if/else
помощью и unlist
dt1 <- dt[, lapply(.SD, function(x) if(is.list(x)) unlist(x) else x)]
str(dt1)
#Classes ‘data.table’ and 'data.frame': 4 obs. of 4 variables:
# $ fromId : chr "89a901291abffff" "89a901295b7ffff" "89a9012809bffff" "89a901285cfffff"
# $ travel_time_p001: int 45 43 38 27
# $ travel_time_p050: int 54 52 44 35
# $ travel_time_p098: int 62 60 55 44
Или без каких-либо проверок
dt[, lapply(.SD, unlist)]
Если нам нужно использовать set
for(j1 in seq_along(dt)) {
cl1 <- class(dt[[j1]])
if(cl1 == 'list') {
set(dt, i = NULL, j = j1, value = unlist(dt[[j1]]))
}
}
str(dt)
#Classes ‘data.table’ and 'data.frame': 4 obs. of 4 variables:
# $ fromId : chr "89a901291abffff" "89a901295b7ffff" "89a9012809bffff" "89a901285cfffff"
# $ travel_time_p001: int 45 43 38 27
# $ travel_time_p050: int 54 52 44 35
# $ travel_time_p098: int 62 60 55 44
Комментарии:
1. Это решение с использованием цикла с
set
работает блестяще. Спасибо