所用r包
library(tidyverse)
library(openxlsx)
数据导入和预处理
adam <- read.csv("青春末期随访24.11.12录入完毕数据.csv")
#空值转为缺失
adam <- adam %>% mutate(across(everything(),~ifelse(.=="",NA,.)))
adam <- adam %>% mutate(completeness = rowSums(!is.na(.)))
#查看重复观测
#从前往后看保留除第一次出现外的重复值
duplicate_rows1 <- adam %>% filter(duplicated(adam[,c("name","idcard")]))
#从后往前看保留除第一次出现外的重复值
duplicate_rows2 <- adam %>% filter(duplicated(adam[,c("name","idcard")], fromLast = TRUE))
#所有重复值观测
all_duplicate_rows <- adam %>% filter(duplicated(adam[,c("name","idcard")]) | duplicated(adam[,c("name","idcard")], fromLast = TRUE))
去重与填补
注:以下去重方法需要变量id有唯一值
方法1.对重复idcard和name保留完整度最高一条观测,相同完整度则保留最新的一条观测
# 定义函数
dedup_by_completeness <- function(data, key_vars,prior_var) {
data <- data %>%
group_by(across(all_of(key_vars))) %>% # 按 key_vars 组合进行分组
slice_max(completeness,with_ties = T) %>% # 保留完整度最高的行
slice_max(.data[[prior_var]],with_ties = T) %>% # 保留最新的行
ungroup() %>%
arrange(id)
return(data)
}
# 调用函数
df_cleaned <- dedup_by_completeness(adam, c("name","idcard"),"id")
方法2 按填写时间顺序填补每个用户最新的那条观测后删除其他观测
df_filled1 <- adam %>%
arrange(id) %>%
group_by(name,idcard) %>%
fill(everything(), .direction = "down") %>% # 使用从上到下填补缺失值
slice_max(id,with_ties = T) %>% # 保留最新的行
ungroup() %>%
mutate(completeness = rowSums(!is.na(.))) %>% #重新计算完整度
arrange(id) #重新排序
方法3.结合方法1和方法2 先挑选最佳保留数据然后用删除数据中的额外信息填补保留数据
df_delete <- setdiff(adam, df_cleaned) #找到方法1剔除的观测
rdf_delete <- df_delete %>% #结合方法2的方法原理更新剔除的观测
arrange(id) %>%
group_by(name,idcard) %>%
fill(everything(), .direction = "down") %>% # 使用上下方向填补缺失值
slice_max(id,with_ties = T) %>% # 保留最新的行
ungroup() %>%
arrange(id)
#将剔除观测中可能含有的额外信息填补到所提出的观测中
df_filled2 <- df_cleaned %>%
left_join(rdf_delete, by = c("name","idcard"), suffix = c("_cleaned", "_other"))%>% #合并需要跟新的数据
mutate(across(ends_with("_cleaned"), ~ coalesce(.x, get(sub("_cleaned", "_other", cur_column()))))) %>% #更新缺失数据
rename_with(~ sub("_cleaned$", "", .), ends_with("_cleaned")) %>% #批量修改列名
select(-ends_with("_other")) %>% #删掉多余列
mutate(completeness = rowSums(!is.na(.))) #重新计算完整度
查看处理后数据完整度
#方法1完整度大于50%数据
df_cleaned %>% filter(completeness>0.5*ncol(.)) %>% nrow()
#方法2完整度大于50%数据
df_filled1 %>% filter(completeness>0.5*ncol(.)) %>% nrow()
#方法3完整度大于50%数据
df_filled2 %>% filter(completeness>0.5*ncol(.)) %>% nrow()