Использование lapply () для заполнения и присвоения имени одному столбцу в списке фреймов данных. - PullRequest
2 голосов
/ 06 мая 2019

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

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

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

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, которые многие базовые функции уже выполняют, и гораздо эффективнее, чем я могу кодировать на этом этапе.

Код psuedo, который я хотел бы, выглядит примерно так:

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 () в этом контексте.

Ответы [ 3 ]

3 голосов
/ 06 мая 2019

Подход с полным основанием 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
1 голос
/ 06 мая 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)
0 голосов
/ 06 мая 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)))

Сказав, что tibble s как современная реализация data.frames предпочтительнее, как и bind_rows overконструкция 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) не имеет атрибута name.

...