我有一些带有唯一ID的受试者数据,每个访问都在数据框的不同行中。某些信息,例如性别或出生年份,可能只在一个访问时收集,但在任何访问中都是相关的。对于未收集信息的访问,该字段将为NA。因此,我创建了一个函数,将给定字段的受试者信息复制到所有访问中,替换NA。这起作用了,但代码很笨重,现在我正在学习整洁数据处理,想要将其纳入其中以使代码更清晰。我还期望它可以加快处理速度,但事实并非如此。
首先,这里是一些玩具数据:
以下内容将产生所需的结果:
在我整理之前,我创建了这段代码,它运行得很好。
现在,
我的实际数据框有15762行,我想为12个变量运行该函数。
我的问题是为什么会有如此巨大的差异?我认为我的第一个函数很业余和笨拙,我认为我正在进行改进。只是因为分组、排列、填充和分组的过程需要更多的计算能力吗?有没有更好的编写方法?我是自学成才,只是想提高自己的技能。
编辑
谢谢您的帮助。这是我最终使用的函数。尽管Cole的
首先,这里是一些玩具数据:
data <- tibble(record_id = c(rep(LETTERS[1:4], 3)),
year1 = c(NA, NA, 2000, 2001, 2002, rep(NA, 7)),
year2 = c(rep(NA, 5), 2003, 2004, 2005, 2006, rep(NA, 3)))
以下内容将产生所需的结果:
data %>%
group_by(id) %>%
arrange(year1, .by_group = T) %>%
fill(year1) %>%
arrange(year2) %>%
fill(year2)
在我整理之前,我创建了这段代码,它运行得很好。
mash.old <- function(data, variable){
x <- data[!is.na(data[,variable]),] %>%
distinct(record_id, .keep_all = T)
x <- as.data.frame(x)
for(i in 1:nrow(data)){
if(is.na(data[i,variable]) &
data[i, "record_id"] %in% x$record_id){
id <- data[i, "record_id"]
data[i,variable] <- x[x$record_id == as.character(id),
variable]
}else{
next
}
}
rm(x, id, i)
return(data)
}
我可以运行
data <- mash.old(data, 'year1')
data <- mash.old(data, 'year2')
并获得所需的结果。
我希望通过允许接受一组变量来执行函数、选择分组变量(受试者id变量名称)以及使用dplyr/tidyr来改进它。于是我创建了这个:
mash.new <- function(data, variables, grouping.var = record_id){
for(i in variables){
data <- data %>%
group_by(!!enquo(grouping.var)) %>%
arrange((!!sym(i)), .by_group = T) %>%
fill(!!sym(i)) %>%
ungroup()
}
return(data)
}
现在,
mash.new(data, c('year1, 'year2'))
将返回预期的结果。对于这个小数据框没有问题。我的实际数据框有15762行,我想为12个变量运行该函数。
mash.old()
花了大约4分钟来完成这个任务。mash.new()
说需要大约3个小时,所以我在大约5分钟左右停止了它。我的问题是为什么会有如此巨大的差异?我认为我的第一个函数很业余和笨拙,我认为我正在进行改进。只是因为分组、排列、填充和分组的过程需要更多的计算能力吗?有没有更好的编写方法?我是自学成才,只是想提高自己的技能。
编辑
谢谢您的帮助。这是我最终使用的函数。尽管Cole的
data.table
版本更快,但我选择坚持使用dplyr
方法,只是因为我熟悉它。mash <- function(data, variables, grouping.var = record_id){
data <- data %>%
arrange(!!enquo(grouping.var)) %>%
group_by(!!enquo(grouping.var)) %>%
mutate_at(vars(!!!variables),
function(x) zoo::na.locf(x[order(x)], na.rm = F)) %>%
ungroup()
return(data)
}
#Note that if there are two different entries for a given subject in a
#variable, this will fill with the data that comes last in the sort order
fill
通常非常慢。我会用zoo::na.locf
替换它,看看会发生什么。 - arg0naut91