一种带代码和工作流程的实用解决方案
https://medium.com/@rcarrillo90?source=post_page---byline--e01c9715b4c7--------------------------------https://towardsdatascience.com/?source=post_page---byline--e01c9715b4c7-------------------------------- Rodrigo M Carrillo Larco, MD, PhD
·发布于Towards Data Science ·阅读时间 7 分钟·2024 年 11 月 27 日
–
在数据集和无尽的数据字典的迷宫中迷失了?告别繁琐的变量查找吧!了解如何通过两个简单的 R 函数,快速识别并提取你所需要的变量,轻松处理多个 SAS 文件。简化你的工作流程,节省时间,让数据准备变得轻松愉快!
作为一名拥有超过七年健康数据处理经验的研究员,我经常收到包含大量数据集的文件夹。例如,想象一下打开一个包含 56 个 SAS 文件的文件夹,每个文件都有独特的数据(见下文示例)。如果你曾经遇到过这种情况,你一定知道那种沮丧的感觉:在成堆的文件中找到特定的变量,感觉就像是在大海捞针。
这张截图由作者拍摄,显示了本地文件夹。文件名已被模糊处理,以保护数据集的机密性。
初看起来,如果你已经知道你的感兴趣变量在哪里,这似乎不是个问题。但通常,你并不知道。虽然通常会提供数据字典,但它通常是一个 PDF 文档,列出了跨多页的变量。找到你需要的内容可能需要搜索(Ctrl+F)第 100 页上的某个变量,结果却发现数据集的名称出现在第 10 页。来回滚动浪费了很多时间。
作者拍摄的数据字典截图。变量名称和标签已被模糊处理,以保持数据集的机密性。
为了避免繁琐的过程,我创建了一个可重复的 R 工作流,可以读取文件夹中的所有数据集,生成一个包含变量名称及其标签的合并数据框(见下方示例),并识别每个变量的位置。这种方法使我的工作更快、更高效。以下是逐步操作的方法。
作者拍摄的names_labels数据集的截图(参见步骤 2)。变量名称和标签已被模糊处理,以保持数据集的机密性。
逐步指南
步骤 1:使用 get_names_labels 函数
首先,使用自定义函数get_names_labels(代码见本文末尾)。该函数需要您存储所有数据集的文件夹路径。
path_file <- "D:/folder1/folder2/folder3/folder_with_datasets/"
get_names_labels(path_file)
步骤 2:生成变量字典
get_names_labels函数将创建一个名为names_labels的数据框(如上例所示),其中包括:
· 变量名称(variable_name)
· 变量标签(variable_label)
· 变量所在的数据集名称(file_name)
根据数据集的数量和大小,这个过程可能需要一两分钟。
步骤 3:搜索变量
一旦生成了names_labels数据框,您就可以搜索所需的变量。筛选variable_name或variable_label列以定位相关术语。例如,如果您在寻找与性别相关的变量,它们可能会被标记为 sex、gender、is_male 或 is_female。
请注意,类似的变量可能出现在多个数据集中。例如,年龄可能出现在主问卷、临床数据集和实验室数据集中。这些变量看起来可能相同,但根据数据的收集方式和地点不同,可能会有所不同。例如:
· 主问卷中的年龄:从所有调查参与者收集。
· 临床/实验室数据集中的年龄:仅限于受邀进一步评估的子集或同意参与的人员。
在这种情况下,主问卷中的变量可能更能代表整个群体。
步骤 4:识别相关数据集
确定所需的变量后,筛选names_labels数据框以识别包含这些变量的原始数据集(file_name)。如果某个变量出现在多个数据集中(例如,ID),您需要确定哪个数据集包含您感兴趣的所有变量。
# Say you want these two variables
variables_needed <- c('ID', 'VAR1_A')
names_labels <- names_labels[which(names_labels$variable_name %in% variables_needed), ]
如果某个变量在多个原始数据集中都能找到(例如,ID),您需要筛选names_labels,只保留包含两个变量的原始数据集(例如,ID和VAR1_A)。在我们的例子中,names_labels数据框将只剩下两行,每行对应我们要查找的两个变量,它们都将在同一个原始数据集中找到。
names_labels <- names_labels %>%
group_by(file_name) %>%
mutate(count = n()) %>%
filter(count >= 2)
步骤 5:提取数据
现在,使用read_and_select函数(位于文末)。传入包含相关变量的原始数据集的名称。这个函数会在你的 R 环境中创建一个新的数据框,仅包含所选择的变量。例如,如果你的变量位于ABC.sas7bdat中,函数将创建一个名为ABC的新数据框,里面只包含那些变量。
unique(names_labels$file_name) # Sanity check, that there is only one dataframe
read_and_select(unique(names_labels$file_name)[1])
步骤 6:清理你的环境
为了保持工作空间整洁,删除不必要的元素,仅保留你需要的新数据框。例如,如果你的相关变量来自ABC.sas7bdat,你将保留过滤后的数据框ABC,它是read_and_select函数的输出结果。
length(unique(names_labels$file_name))
names_labels$file_name <- str_extract(names_labels$file_name, "[^.]+")
rm(list = setdiff(ls(), c(unique(names_labels$file_name))))
步骤 7:合并多个数据集(可选)
如果你的相关变量分布在多个数据集中(例如ABC和DEF),你可以将它们合并。使用唯一标识符,如ID,将数据集合并成一个单一的数据框。最终结果将是一个统一的数据框,包含你所需的所有变量。你将获得一个df数据框,里面包含所有观察值,但只有你需要的变量。
# Get a list with the names of the dataframes in the environment (“ABC” and “DEF”)
object_names <- ls()
# Get a list with the actual dataframe
object_list <- mget(object_names)
# Reduce the dataframes in the list (“ABC” and “DEF”) by merging conditional on the unique identifier (“ID”)
df <- Reduce(function(x, y) merge(x, y, by = "ID", all = TRUE), object_list)
# Clean your environment to keep only the dataframes (“ABC” and “DEF”) and a new dataframe “df” which will contain all the variables you needed.
rm(object_list, object_names)
为什么这个工作流程有效?
这种方法节省了时间,并将你的工作组织成一个单一、可重复的脚本。如果你后来决定添加更多变量,只需重新访问步骤 2 和 3,更新你的列表,并重新运行脚本。这种灵活性在处理大数据集时非常宝贵。虽然你仍然需要查阅文档以理解变量定义和数据收集方法,但这种工作流程减少了定位和准备数据的工作量。处理多个数据集不必让人感到不知所措。通过使用像get_names_labels和read_and_select这样的自定义函数,你可以简化数据准备的工作流程。
你是否在处理多个数据集时遇到过类似的挑战?如果有,欢迎在评论中分享你的想法或小贴士,或者如果你觉得这篇文章有帮助,给它点赞。让我们继续交流,互相学习!
以下是两个自定义函数。将它们保存在一个R脚本文件中,并在需要时将脚本加载到你的工作环境中。例如,你可以将文件保存为_Functions.R,以便随时访问。
# You can load the functions as
source('D:/Folder1/Folder2/Folder3/_Functions.R')
library(haven)
library(tidyverse)
library(stringr)
## STEPS TO USE THESE FUNCTIONS:
## 1\. DEFINE THE OBJECT 'PATH_FILE', WHICH IS A PATH TO THE DIRECTORY WHERE
## ALL THE DATASETS ARE STORED.
## 2\. APPLY THE FUNCTION 'get_names_labels' WITH THE PATH. THE FUNCTION WILL
## RETURN A DATAFRAME NAMES 'names_labels'.
## 3\. THE FUNCTION WILL RETURN A DATASET ('names_labels) SHOWING THE NAMES OF
## THE VARIABLES, THE LABELS, AND THE DATASET. VISUALLY/MANUALLY EXPLORE THE
## DATASET TO SELECT THE VARIABLES WE NEED. CREATE A VECTOR WITH THE NAMES
## OF THE VARIABLES WE NEED, AND NAME THIS VECTOR 'variables_needed'.
## 4\. FROM THE DATASET 'names_labels', KEEP ONLY THE ROWS WITH THE VARIABLES WE
## WILL USE (STORED IN THE VECTOR 'variables_needed').
## 5\. APPLY THE FUNCTION 'read_and_select' TO EACH OF THE DATASETS WITH RELEVANT
## VARIABLES. THIS FUNCTION WILL ONLY NEED THE NAME OF THE DATASET, WHICH IS
## STORED IN THE LAST COLUMN OF DATASET 'names_labels'.
### FUNCTION TO 1) READ ALL DATASETS IN A FOLDER; 2) EXTRACT NAMES AND LABELS;
### 3) PUT NAMES AND LABELS IN A DATASET; AND 4) RETURN THE DATASET. THE ONLY
### INPUT NEEDED IS A PATH TO A DIRECTORY WHERE ALL THE DATASETS ARE STORED.
get_names_labels <- function(path_file){
results_df <- list()
sas_files <- c(
list.files(path = path_file, pattern = "\\.sas7bdat$")
)
for (i in 1:length(sas_files)) {
print(sas_files[i])
# Read the SAS file
sas_data <- read_sas(paste0(path_file, sas_files[i]))
sas_data <- as.data.frame(sas_data)
# Get the variable names and labels
var_names <- names(sas_data)
labels <- sas_data %>%
map(~attributes(.)$label) %>%
map_chr(~ifelse(is.null(.), NA, .))
# Combine the variable names and labels into a data frame
var_df <- data.frame(
variable_name = var_names,
variable_label = labels,
file_name = sas_files[i],
stringsAsFactors = FALSE
)
# Append the results to the overall data frame
results_df[[i]] <- var_df
}
results_df <- do.call(rbind, results_df)
#return(results_df)
assign('names_labels', results_df, envir = .GlobalEnv)
}
################################################################################
### FUNCTION TO READ EACH DATASET AND KEEP ONLY THE VARIABLES WE SELECTED; THE
### FUNCTION WILL SAVE EACH DATASET IN THE ENVIRONMENT. THE ONLY INPUNT IS THE
### NAME OF THE DATASET.
read_and_select <- function(df_file){
df_tmp <- read_sas(paste0(path_file, df_file))
df_tmp <- df_tmp %>%
select(unique(names_labels[which(names_labels$file_name == df_file), ]$variable_name)) %>%
as.data.frame()
assign(str_extract(df_file, "[^.]+"), df_tmp,envir = .GlobalEnv)
}
################################################################################
你可以在 LinkedIn 上找到我,期待与你联系并讨论。
1543

被折叠的 条评论
为什么被折叠?



