R использование lapply () для заполнения и имени одного столбца в списке фреймов данных

После некоторого поиска я не могу найти гладкое решение в стиле R-esque.

У меня есть список векторов, которые я хочу преобразовать в фреймы данных, и добавить столбец с именами векторов. Я не могу сделать это с помощью cbind () и melt () для одного кадра данных. B / c есть векторы с разным количеством строк.

Базовый пример:

list<-list(a=c(1,2,3),b=c(4,5,6,7))
var<-"group"

Я придумал и работаю:

list<-lapply(list, function(x) data.frame(num=x,grp=""))

for (j in 1:length(list)){
  list[[j]][,2]<-names(list[j])
  names(list[[j]])[2]<-var
}

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

Мне нужен псевдокод:

list<-lapply(list, function(x) data.frame(num=x,get(var)=names(x))

Есть ли чистый способ сделать это?

Второй тесно связанный вопрос: если у меня уже есть список фреймов данных, почему так сложно переназначить значения и имена столбцов с помощью lapply ()?

Итак, используя что-то вроде:

list<-list(a=data.frame(num=c(1,2,3),grp=""),b=data.frame(num=c(4,5,6,7),grp=""))
var<-"group"

#pseudo code
list<-lapply(list, function(x) x[,2]<-names(x)) #populate second col with name of df[x]
list<-lapply(list, function(x) names[[x]][2]<-var) #set 2nd col name to 'var'

Первая строка псевдокода выдает ошибку о совпадении длин строк. Почему lapply () не просто выполняет цикл и не повторяет имена (x), как та же функция в одном фрейме данных в цикле for?

Для второй строки, насколько я понимаю, я могу использовать setNames (), чтобы переназначить все имена столбцов, но как мне заставить это работать только для одного из имен столбцов?

Большое спасибо за любые идеи или ссылки на другие темы, которые охватывают это и помогают мне понять поведение lapply () в этом контексте.


person jsol    schedule 06.05.2019    source источник
comment
Будьте осторожны, называя свои объекты после встроенных функций и объектов, например list.   -  person coffeinjunky    schedule 06.05.2019
comment
@coffeinjunky, конечно, спасибо. просто пытаюсь привести пример. ls было бы лучше.   -  person jsol    schedule 08.05.2019


Ответы (3)


Полный базовый подход R без использования циклов

> l<-list(a=c(1,2,3),b=c(4,5,6,7))
> data.frame(grp=rep(names(l), lengths(l)), num=unlist(l), row.names = NULL)
  grp num
1   a   1
2   a   2
3   a   3
4   b   4
5   b   5
6   b   6
person Jilber Urbina    schedule 06.05.2019

В связи с вашим первым / основным вопросом вы можете использовать для этой цели функцию enframe из пакета tibble

library(tibble)
library(tidyr)
library(dplyr)

l<-list(a=c(1,2,3),b=c(4,5,6,7))

l %>% 
  enframe(name = "group", value="value") %>% 
  unnest(value) %>% 
  group_split(group)
person MrNetherlands    schedule 06.05.2019

Попробуй это:

library(dplyr)
mylist <- list(a = c(1,2,3), b = c(4,5,6,7))
bind_rows(lapply(names(mylist), function(x) tibble(grp = x, num = mylist[[x]])))
# A tibble: 7 x 2
  grp     num
  <chr> <dbl>
1 a         1
2 a         2
3 a         3
4 b         4
5 b         5
6 b         6
7 b         7

По сути, это решение на основе lapply, в котором вы перебираете имена своего списка, а не сами отдельные элементы списка. Если вы предпочитаете делать все на базе R, обратите внимание, что приведенное выше эквивалентно

do.call(rbind, lapply(names(mylist), function(x) data.frame(grp = x, num = mylist[[x]], stringsAsFactors = F)))

При этом tibbles как современная реализация data.frames предпочтительнее, как и bind_rows над конструкцией do.call(rbind....

Что касается второго вопроса, обратите внимание на следующее:

lapply(mylist, function(x) str(x))
 num [1:3] 1 2 3
 num [1:4] 4 5 6 7
....
lapply(mylist, function(x) names(x))
$a
NULL
$b
NULL

Здесь вы видите, что функция внутри lapply получает элементы mylist. В этом случае он должен работать с числовым вектором. Что касается функции, вызываемой внутри lapply, у нее нет никакого имени. Чтобы подчеркнуть это, примите во внимание следующее:

names(c(1,2,3))
NULL

То же самое: вектор c(1,2,3) не имеет атрибута имени.

person coffeinjunky    schedule 06.05.2019