R 使用 lapply() 填充和命名数据框列表中的一列
R use of lapply() to populate and name one column in list of dataframes
找了一段时间,没找到流畅的R类解法。
我有一个向量列表,我想将其转换为数据帧并添加一个包含向量名称的列。我无法将 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() 不像单个数据帧上的相同函数在 for 循环中那样循环并重复 names(x)?
对于第二行,据我所知,我可以使用 setNames() 来重新分配所有列名,但是我如何只对其中一个列名进行这项工作?
非常感谢任何想法或指向涵盖此内容的其他线程并帮助我理解 lapply() 在这种情况下的行为。
关于您的 first/main 问题,您可以使用包 tibble
中的函数 enframe
来达到此目的
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)
试试这个:
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
的解决方案,您可以在其中迭代列表的名称,而不是单个列表元素本身。如果你更喜欢在 base R 中做所有事情,请注意以上等同于
do.call(rbind, lapply(names(mylist), function(x) data.frame(grp = x, num = mylist[[x]], stringsAsFactors = F)))
话虽如此,tibble
s 作为 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)
没有名称属性。
不使用循环的完整 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
找了一段时间,没找到流畅的R类解法。
我有一个向量列表,我想将其转换为数据帧并添加一个包含向量名称的列。我无法将 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() 不像单个数据帧上的相同函数在 for 循环中那样循环并重复 names(x)?
对于第二行,据我所知,我可以使用 setNames() 来重新分配所有列名,但是我如何只对其中一个列名进行这项工作?
非常感谢任何想法或指向涵盖此内容的其他线程并帮助我理解 lapply() 在这种情况下的行为。
关于您的 first/main 问题,您可以使用包 tibble
中的函数 enframe
来达到此目的
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)
试试这个:
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
的解决方案,您可以在其中迭代列表的名称,而不是单个列表元素本身。如果你更喜欢在 base R 中做所有事情,请注意以上等同于
do.call(rbind, lapply(names(mylist), function(x) data.frame(grp = x, num = mylist[[x]], stringsAsFactors = F)))
话虽如此,tibble
s 作为 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)
没有名称属性。
不使用循环的完整 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