迭代修改嵌套DataFrame遇赋值无效问题,求lapply优化方案
问题:批量修改列表中DataFrame的列并同步回原列表
我有一个列名完全一致的DataFrame列表,想遍历这些DataFrame,修改其中一列后同步回原列表。知道用普通循环的方式效果不好,求用lapply的更优解法!
循环无效的示例代码
df <- list( '2020-01-01' = data.frame(value = c(3,5,7,8), wt = c(1,1,1,1)), '2020-02-01' = data.frame(value = c(90,90,98,91), wt = c(1,1,1,1)), '2020-03-01' = data.frame(value = c(0,10,3,8), wt = c(1,1,1,1))) for(i in df){ data <- data.frame( val = i$value, wt = i$wt) %>% mutate(wt = ifelse(val > 95 | val < 5, 100, 1)) # 循环内的修改生效 print(data) # 但此赋值操作无效果 i = data } print(df)
可以看到循环里的i = data完全起不到修改原列表的作用,但如果直接指定列表中的单个DataFrame(比如df$'2020-01-01')进行赋值,就能正常生效:
单个DataFrame修改生效的示例
data <- data.frame(val = df$`2020-01-01`$value, wt = df$`2020-01-01`$wt) %>% mutate(wt = ifelse(val > 95 | val < 5, 100, 1)) df$`2020-01-01` = data df
解决方案:使用lapply批量处理
lapply是R中处理列表的高效工具,它会遍历列表中的每个元素,应用自定义函数后返回修改后的新列表,直接覆盖原列表即可完成同步:
library(dplyr) df <- list( '2020-01-01' = data.frame(value = c(3,5,7,8), wt = c(1,1,1,1)), '2020-02-01' = data.frame(value = c(90,90,98,91), wt = c(1,1,1,1)), '2020-03-01' = data.frame(value = c(0,10,3,8), wt = c(1,1,1,1))) # 使用lapply遍历并修改每个DataFrame df <- lapply(df, function(x) { x %>% mutate(wt = ifelse(value > 95 | value < 5, 100, 1)) }) print(df)
为什么普通循环无效?
在for(i in df)的循环中,i是原DataFrame的副本,不是引用。修改i只是修改了临时副本,不会影响原列表中的元素。而lapply会直接对每个元素应用函数,返回所有修改后的结果组成的新列表,将其赋值给原变量后,自然完成了原列表的同步更新。
额外优化点
- 不需要额外创建
val列,直接用原列value进行判断即可,简化代码 - 如果需要保留原始数据,可将结果赋值给新变量(比如
df_modified <- lapply(...)),避免覆盖原列表
内容的提问来源于stack exchange,提问作者Squan Schmaan
相关产品推荐
相关产品推荐

