为数据框补全缺失年份(重塑):求基于管道符的优化方案
为缺失年份的企业补全NA营收的R语言优化实现方案
我现在有这么一个R语言数据框:
df <- structure(list( year = c(2001, 2001, 2002, 2003, 2001, 2002, 2003), name = c("A", "B", "B", "B", "C", "C", "C"), revenue = c(10, 20, 30, 40, 30, 40, 50)), .typeOf = c("numeric", "factor", "numeric"), row.names = c(NA, -7L), class = "data.frame")
里面第一列是年份,第二列是企业名称,第三列是营收。能看到企业"A"只有2001年的记录,而B、C两家的年份数据就完整很多。我需要给"A"补上2002、2003年的行,对应的营收设为NA。
之前我用这段代码实现了需求:
df %>% spread(year, revenue) %>% gather(year, revenue, 2:ncol(.)) %>% arrange(name) %>% View()
小数据集上跑起来没问题,但总觉得编程层面应该还有更优的写法。想请教下用melt、cast(比如dcast)这类方法的实现方案,而且要支持管道符%>%的写法。
推荐方案1:用tidyr的complete()(最简洁高效)
其实tidyr包里的complete()就是专门解决这类补全缺失组合需求的,比spread+gather的写法直接太多,代码可读性也强:
library(tidyr) library(dplyr) df %>% complete(name, year = full_seq(year, 1)) %>% arrange(name)
解释:
complete()会自动生成name和year所有可能的组合,缺失的revenue会自动填充为NA;full_seq(year, 1)用来提取数据中所有连续的年份,这里年份是2001-2003,也可以直接写2001:2003,但用full_seq更灵活,哪怕年份不连续也能自动识别全量范围。
方案2:用reshape2的dcast()+melt()组合
如果一定要用reshape2包里的dcast和melt,也可以这么写:
library(reshape2) library(dplyr) df %>% dcast(name ~ year, value.var = "revenue") %>% melt(id.vars = "name", variable.name = "year", value.name = "revenue", na.rm = FALSE) %>% mutate(year = as.numeric(as.character(year))) %>% arrange(name)
步骤分解:
dcast先把数据转成宽表:每个企业一行,年份作为列,缺失的年份对应的营收自动填NA;melt再把宽表转回长表,na.rm = FALSE确保保留带NA的行;- 因为
dcast处理后年份会变成因子类型,所以要转成数值型; - 最后按企业名称排序。
方案3:用expand()+left_join()(逻辑最直观)
另一种思路是先生成所有企业-年份的完整组合框架,再左连接原数据:
library(dplyr) df %>% expand(name, year = full_seq(year, 1)) %>% left_join(df, by = c("name", "year")) %>% arrange(name)
解释:
expand()先创建出所有可能的企业-年份组合;left_join把原数据的营收匹配到对应组合上,没有匹配到的就会填充为NA,逻辑非常直白,新手也容易理解。
方案对比
complete():最推荐,属于tidyverse的标准解决方案,代码简洁语义清晰,大数据集上效率也不错;- dcast+melt:偏向传统reshape2的处理思路,但需要额外处理年份类型转换,代码稍显繁琐;
- expand+left_join:逻辑最直观,适合对join操作更熟悉的用户,大数据集表现也稳定。
内容的提问来源于stack exchange,提问作者Jeparov
相关产品推荐
相关产品推荐

