如何修改多个数据框而不列出它们然后使用 lapply?

Posted

技术标签:

【中文标题】如何修改多个数据框而不列出它们然后使用 lapply?【英文标题】:How to modify multiple data frames without making a list of them and then using lapply? 【发布时间】:2018-02-16 05:45:29 【问题描述】:

我有 20 个数据框,我想在每个数据框中以相同的方式格式化同一列。当然,我可以创建一个 list 的 dfs,然后使用 lapply。相反,我的目标是修改 dfs,以便最终我不必将它们作为列表的元素访问,而是作为 dfs 访问。这是一个例子:

df1 <- data.frame(col1 = rnorm(5), col2 = rnorm(5))
df2 <- data.frame(col1 = rnorm(5), col2 = rnorm(5))

现在,假设我想给df1df2col1 的每个值加1。当然可以了

df_list <- lapply(list(df1, df2), function(df) 
  df$col1 <- df$col1 + 1
  return(df)
)

但现在df1 返回原始 df 而不是修改后的。怎么做?

【问题讨论】:

如果您需要更新df1,请在设置df_list 的名称后使用list2env(df_list, envir = .GlobalEnv)names(df_list) &lt;- c("df1", "df2") 如果您不需要创建list,则使用@ 987654335@ 循环与assign 为什么将这些作为单独的变量如此重要?为什么一开始没有在列表中创建它们?迭代环境中的对象需要get/assign which isn't ideal。如果您将相关项目保留在列表中,一切都会正常工作。 通过将 dfs 分开,我可以使用 RStudio 的数据查看器。最重要的是,显式子集(例如df$col1)比子集复杂列表更方便。 【参考方案1】:

您可以通过这样的循环来避免该函数(及其临时环境):

df1 <- data.frame(col1 = 1:5, col2 = rnorm(5))
df2 <- data.frame(col1 = rep(0, 5), col2 = rnorm(5))

df1 # before
for (d in c("df1", "df2")) 
  eval(parse(text = paste(d, "[['col1']] <- ", d, "[['col1']] + 1")))

df1 # after

选项 2:

df1 <- data.frame(col1 = 1:5, col2 = rnorm(5))
df2 <- data.frame(col1 = rep(0, 5), col2 = rnorm(5))

df1 # before
df2 # before
eval(parse(text = unlist(lapply(c("df1", "df2"), function(x) 
  expr.dummy <- quote(df$col1 <- df$col1 +1) # df will be replaced by df1, df2
  gsub("df", x, deparse(expr.dummy))
  ))))
df1 # after
df2 # after

【讨论】:

【参考方案2】:

您可以在这个问题中使用来自@g-grothendieck 的技巧:

http://***.com/questions/1826519/how-to-assign-from-a-function-which-returns-more-than-one-value

然后这样做:

list[df1, df2] <- lapply(list(df1, df2), function(df) 
          df$col1 <- df$col1 + 1
          return(df)
        )

黑客攻击

list <- structure(NA,class="result")
"[<-.result" <- function(x,...,value) 
  args <- as.list(match.call())
  args <- args[-c(1:2,length(args))]
  length(value) <- length(args)
  for(i in seq(along=args)) 
    a <- args[[i]]
    if(!missing(a)) eval.parent(substitute(a <- v,list(a=a,v=value[[i]])))
  
  x

完整代码和结果

df1 <- data.frame(col1 = rnorm(5), col2 = rnorm(5))
# col1       col2
# 1 -0.5451934  0.5043287
# 2 -1.4047701 -0.1184588
# 3  0.1745109  0.8279085
# 4 -0.5066673 -0.3269411
# 5  0.4838625 -0.3895784
df2 <- data.frame(col1 = rnorm(5), col2 = rnorm(5))
# col1        col2
# 1  0.4168078 -0.44654445
# 2 -1.9991098 -0.06179699
# 3 -1.0625996  1.21098946
# 4  0.4977718  0.45834008
# 5 -1.6181048  0.97917877

list[df1, df2] <- lapply(list(df1, df2), function(df) 
  df$col1 <- df$col1 + 1
  return(df)
)
# > df1
# col1       col2
# 1  0.4548066  0.5043287
# 2 -0.4047701 -0.1184588
# 3  1.1745109  0.8279085
# 4  0.4933327 -0.3269411
# 5  1.4838625 -0.3895784
# > df2
# col1        col2
# 1  1.41680778 -0.44654445
# 2 -0.99910976 -0.06179699
# 3 -0.06259959  1.21098946
# 4  1.49777179  0.45834008
# 5 -0.61810483  0.97917877

【讨论】:

【参考方案3】:

基于 OP 代码的一个选项是在命名 list 元素后使用 list2env

names(df_list) <- paste0("df", 1:2)
list2env(df_list, envir = .GlobalEnv)

如果我们需要避免创建list(建议有一个list的数据集,而不是在全局环境中创建单个对象),那么使用assignfor循环

for(obj in paste0('df', 1:2)) 
     assign(obj, `[<-`(get(obj), 'col1', value = get(obj)[['col1']] +1))
 

【讨论】:

以上是关于如何修改多个数据框而不列出它们然后使用 lapply?的主要内容,如果未能解决你的问题,请参考以下文章

在闪亮的 server.R 中更新数据框而不重新启动应用程序

单击保存按钮后如何在用户窗体中添加依赖于另一个组合框的excel vba组合框而不影响清除数据功能

合并两个数据框而不重复熊猫

如何在 MS ACCESS 中打开定时消息框而不创建其他窗口

Python Streamlit - 过滤熊猫数据框而不重新运行整个脚本

如果出现错误,请保留警告框而不关闭