嵌套lapply是否不适用于操作向量单个元素?R代码改写疑问
问题:用嵌套
lapply改写循环后无法返回完整数据集,如何解决? 原问题背景
我有一个长度为12的列表hh_temp,每个元素都是dataframe。原本用嵌套for循环计算max_min_sum列的5天连续和,若和大于2则给max_min_sum_5days对应位置赋值1,否则0:
for(i in 1:length(hh_temp)){ hh_temp_save = hh_temp[[i]] for(j in 4:nrow(hh_temp_save)){ hh_temp_save$max_min_sum_5days[j] = ifelse(sum(hh_temp_save$max_min_sum[(j-4):j])>2,1,0) hh_temp[[i]] = hh_temp_save } }
尝试用嵌套lapply改写后,只能返回被操作的向量,拿不到完整数据集。想知道怎么返回完整数据集,以及嵌套lapply是不是不适合操作向量中的单个元素?
数据集结构
> str(hh_temp) List of 12 $ : tibble [3,684 × 36] (S3: tbl_df/tbl/data.frame) ..$ max_min_sum : num [1:3684] 0 0 0 0 0 0 0 0 0 0 ... ..$ max_min_sum_5days : num [1:3684] NA NA NA NA NA NA NA NA NA NA ... $ : tibble [3,684 × 36] (S3: tbl_df/tbl/data.frame) ..$ max_min_sum : num [1:3684] 0 0 0 0 0 0 0 0 0 0 ... ..$ max_min_sum_5days : num [1:3684] NA NA NA NA NA NA NA NA NA NA ... # 重复12次 # max_min_sum是二元变量
示例数据
df = data.frame(a = as.factor(c(1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1,0,1)), b = rep(NA,18)) sample_list = list(df,df,df,df,df,df)
预期结果
计算a列连续5个元素的和,若和大于2则给b列对应位置赋值1,否则0,示例如下:
| a | b |
|---|---|
| 1 | NA |
| 1 | NA |
| 1 | NA |
| 1 | NA |
| 0 | 1 |
| 0 | 1 |
| 0 | 0 |
比如第5个a元素对应的连续和是4,大于2,所以b对应位置为1。
解决方案
1. 正确使用lapply返回完整数据集
lapply完全可以用来操作列表中的dataframe并返回完整数据集,核心是要在每个lapply的函数中返回修改后的整个dataframe,而不是只返回被修改的向量。
针对需求的改写代码如下:
# 先安装并加载zoo包(如果未安装) # install.packages("zoo") library(zoo) hh_temp <- lapply(hh_temp, function(df) { # 确保max_min_sum是数值型(如果是因子需转换) df$max_min_sum <- as.numeric(df$max_min_sum) # 计算滚动5项和,前4个位置保留NA roll_sum <- rollsum(df$max_min_sum, k = 5, fill = NA, align = "right") # 生成目标列 df$max_min_sum_5days <- ifelse(roll_sum > 2, 1, 0) # 返回修改后的完整dataframe return(df) })
2. 为什么你的嵌套lapply只返回向量?
大概率是你在内部lapply中只返回了修改后的max_min_sum_5days向量,没有把它放回原dataframe并返回整个数据集。比如错误写法类似:
# 错误示例:仅返回向量,丢失原数据集其他列 hh_temp <- lapply(hh_temp, function(df) { lapply(4:nrow(df), function(j) { sum_val <- sum(df$max_min_sum[(j-4):j]) ifelse(sum_val > 2, 1, 0) }) })
这种写法会把每个dataframe变成向量列表,自然丢失原数据集结构。
3. 更高效的替代方案:用滚动窗口函数替代循环
原for循环效率较低,数据量大时更明显。用slider包的滚动函数也能实现需求,代码更直观:
# 先安装并加载slider包(如果未安装) # install.packages("slider") library(slider) hh_temp <- lapply(hh_temp, function(df) { df$max_min_sum <- as.numeric(df$max_min_sum) # .before=4表示取当前行及前4行(共5行),.complete=TRUE确保只有完整窗口才计算 roll_sum <- slide_dbl(df$max_min_sum, ~sum(.x), .before = 4, .complete = TRUE) df$max_min_sum_5days <- ifelse(roll_sum > 2, 1, 0) return(df) })
内容的提问来源于stack exchange,提问作者doraemon
相关产品推荐
相关产品推荐

