如何在R中使用Apply函数为列表内的数据框添加对应值的新列
问题描述
我有两个长度相同的列表:一个存储若干dataframe,另一个存储字符串。想为每个dataframe添加一列,列值为字符串列表中对应的元素。示例如下:
# 初始数据框 df1 <- data.frame(v1 = c(1,2,3), v2 = c("a","b","c")) df2 <- data.frame(v1 = c(7,8,9), v2 = c("x","y","z")) dflist <- list(df1, df2) # 待添加到各数据框的值列表 nameslist <- c('first df value', 'second df value') # 期望输出 df1$v3 <- nameslist[1] # v1 v2 v3 # 1 1 a first df value # 2 2 b first df value # 3 3 c first df value df2$v3 <- nameslist[2] # v1 v2 v3 # 1 7 x second df value # 2 8 y second df value # 3 9 z second df value
用循环可以轻松实现,但想知道如何用Apply系列函数完成?我尝试了以下代码,但没得到预期结果:
output <- lapply(seq_along(dflist), function(i) dflist[[i]]$test = nameslist[[i]]) # 返回对应nameslist的字符向量列表 output <- mapply(function(df, name) df$test = name, dflist, nameslist) # 返回nameslist的单个字符向量
解决方案
你的思路方向是对的,问题出在匿名函数里只做了赋值操作,但没有返回修改后的dataframe。下面是几种可行的写法:
方法1:使用mapply(推荐,直接配对两个列表元素)
output <- mapply(function(df, name) { df$v3 <- name # 为当前dataframe添加新列 df # 返回修改后的dataframe }, dflist, nameslist, SIMPLIFY = FALSE)
SIMPLIFY = FALSE是关键参数,确保返回结果保持列表结构,不会被自动简化为其他类型。- 运行后
output就是包含修改后dataframe的列表,output[[1]]对应修改后的df1,output[[2]]对应修改后的df2。
方法2:使用lapply(通过索引遍历)
output <- lapply(seq_along(dflist), function(i) { df <- dflist[[i]] df$v3 <- nameslist[i] df })
- 先取出当前索引对应的dataframe,添加新列后返回,即可得到完整的修改后数据框列表。
方法3:使用purrr包的map2(tidyverse风格)
如果你习惯tidyverse语法,purrr::map2专门处理两个长度相同的列表配对操作:
library(purrr) output <- map2(dflist, nameslist, ~{ .x$v3 <- .y .x })
失败原因说明
你之前的匿名函数只执行了df$test = name,在R中赋值操作的返回值是被赋予的值(也就是name),而非修改后的dataframe。因此最终得到的是nameslist的元素,而非带新列的dataframe列表。只要在函数末尾返回修改后的dataframe即可解决问题。
内容的提问来源于stack exchange,提问作者reidj
相关产品推荐
相关产品推荐

