R语言如何对列表内数据框的指定列批量应用na.locf填充
问题背景
我有一个包含数千个dataframe的列表,单个数据框的结构如下所示:
structure(list(frame = c(222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252), room = c("B6", NA, NA, NA, NA, "B6", NA, NA, "B6", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "B6", NA, NA, NA, NA, NA, NA, "B6" ), id = c(2, NA, NA, NA, NA, 85, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 32, NA, NA, NA, NA, NA, NA, 1), id_prob = c(0.710559149006359, NA, NA, NA, NA, 0.676624962451645, NA, NA, 0.650006199807849, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.668218888964693, NA, NA, NA, NA, NA, NA, 0.786722974412071), x = c(1606, NA, NA, NA, NA, 1319, NA, NA, 1636, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 1316.75, NA, NA, NA, NA, NA, NA, 656.5), y = c(-472.25, NA, NA, NA, NA, -516.5, NA, NA, -463.5, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -520, NA, NA, NA, NA, NA, NA, -941), orientation = c(84.5596680381038, NA, NA, NA, NA, 51.3401926511951, NA, NA, 71.565048727047, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 63.4349516145757, NA, NA, NA, NA, NA, NA, 120.963756691571), area = c(-133, NA, NA, NA, NA, -98, NA, NA, -140, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -130, NA, NA, NA, NA, NA, NA, -166)), row.names = c(NA, -31L), class = c("tbl_df", "tbl", "data.frame"))
我编写了如下代码,可在连续NA值的最大间隔小于20行时填充对应位置的缺失值:
df[c('id','x','y')] <- na.locf(df[c('id','x','y')], na.rm = F, maxgap = 20)
该代码在单个数据框上运行效果完全符合预期,仅填充id、x、y三列的NA值,其余列保持原有NA不变,处理后结果结构如下:
structure(list(frame = c(222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252), room = c("B6", NA, NA, NA, NA, "B6", NA, NA, "B6", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "B6", NA, NA, NA, NA, NA, NA, "B6" ), id = c(2, 2, 2, 2, 2, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 1), id_prob = c(0.710559149006359, NA, NA, NA, NA, 0.676624962451645, NA, NA, 0.650006199807849, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 0.668218888964693, NA, NA, NA, NA, NA, NA, 0.786722974412071), x = c(1606, 1606, 1606, 1606, 1606, 1319, 1319, 1319, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1316.75, 1316.75, 1316.75, 1316.75, 1316.75, 1316.75, 1316.75, 656.5), y = c(-472.25, -472.25, -472.25, -472.25, -472.25, -516.5, -516.5, -516.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -463.5, -520, -520, -520, -520, -520, -520, -520, -941), orientation = c(84.5596680381038, NA, NA, NA, NA, 51.3401926511951, NA, NA, 71.565048727047, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 63.4349516145757, NA, NA, NA, NA, NA, NA, 120.963756691571), area = c(-133, NA, NA, NA, NA, -98, NA, NA, -140, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -130, NA, NA, NA, NA, NA, NA, -166)), row.names = c(NA, -31L), class = c("tbl_df", "tbl", "data.frame"))
出于区分原始数据和填充数据的需求,必须保证仅填充id、x、y这3个指定列的NA值,其余所有列的NA值保持原样不做修改。但将该逻辑应用到列表内的所有数据框时遇到了问题:
- 第一种写法返回的结果会丢失除
id、x、y外的所有其他列,代码如下:
test <- lapply(list, function(x) na.locf(x[c('id','x','y')],na.rm = F, maxgap = 20))
- 第二种写法会填充数据框所有列的NA值,不符合仅填充指定列的要求,代码如下:
test <- lapply(list, function(x) na.locf(x,na.rm = F, maxgap = 20))
需要找到能将单数据框填充逻辑正确批量应用到整个列表所有数据框的方法。
解决方法
直接在lapply的匿名函数中复用单数据框的赋值逻辑即可,不要返回列子集,也不要直接对整个数据框执行na.locf。
注意:不要用list作为列表变量名,这是R内置的基础函数名,会引发命名冲突,以下示例将列表对象命名为df_list。
# 先加载zoo包,na.locf来自该包 library(zoo) test <- lapply(df_list, function(x) { # 仅对指定三列做填充,赋值回原数据框对应位置 x[c('id','x','y')] <- na.locf(x[c('id','x','y')], na.rm = F, maxgap = 20) # 返回完整的修改后数据框 return(x) })
错误原因说明
- 第一种错误写法中,匿名函数最终返回的是
na.locf处理后的三列子集,没有保留其他列,因此结果会丢失其余字段 - 第二种错误写法直接将整个数据框传入
na.locf,相当于对所有列统一执行填充操作,因此会修改不需要处理的列 - 上述正确写法完全对齐单数据框的操作逻辑:仅取出目标列做填充,再将填充结果写回原数据框对应位置,最后返回完整数据框,既不会丢失列,也不会修改非目标列的NA值。
内容的提问来源于stack exchange,提问作者cebola
相关产品推荐
相关产品推荐

