2026年4月7日 研究日志¶
今日也在数据清洗中,对的,作为一个数据科学家,实际上数据清理占了很大量的工作时间,说真的,对我来说,时间分配上读文献做文书工作占4成,数据清理占4成,实际顶多有2成时间是在编写代码进行数据分析。数据算不上保密,因为今天用的是公开的GEO数据集GSE135133,这是个单细胞测序数据集,准确说是单核测序数据集。不过这个大型数据集我可放不上来,今天就展示一下我的清理pipeline吧。注意,这仅仅是一个自动化的,修复通用问题的pipeline,而现实中每个数据集都有可能有自己独特的错误,不管有多么自动化的工具,都一定自己留心,对自己的数据负责,才能对自己的结论负责。
flowchart TD
A[raw_df
原始数据框] --> B[clean_colnames
统一列名]
B --> C[drop_empty
删除空行空列]
C --> D[fix_types
修复列类型]
D --> E[normalize_strings
标准化字符串]
E --> F[remove_duplicates
去除重复行]
F --> G[impute_missing
填补缺失值]
G --> H[extra_steps
可选额外步骤]
H --> I[df_clean
清洗后的数据框]
In [ ]:
library(janitor)
library(tidyr)
library(dplyr)
library(stringr)
# ================================
# 1. 清洗函数
# ================================
clean_colnames <- function(df) {
names(df) <- janitor::make_clean_names(names(df))
df
}
drop_empty <- function(df) {
df %>% janitor::remove_empty(c("rows", "cols"))
}
fix_types <- function(df) {
df %>% mutate(across(where(is.character), ~ trimws(.x)))
}
normalize_strings <- function(df) {
df %>% mutate(across(where(is.character), ~ tolower(.x)))
}
remove_duplicates <- function(df) {
df %>% distinct()
}
impute_missing <- function(df) {
df %>% mutate(across(where(is.numeric), ~ ifelse(is.na(.x), median(.x, na.rm = TRUE), .x)))
}
# ================================
# ================================
# 2. 日志函数
# ================================
log_step <- function(msg) {
cat(sprintf("[INFO] %s\n", msg))
}
# ================================
# 3. 主 Pipeline
# ================================
clean_pipeline <- function(df,
do_colnames = TRUE,
do_drop_empty = TRUE,
do_fix_types = TRUE,
do_normalize = TRUE,
do_dedup = TRUE,
do_impute = TRUE,
extra_steps = list()) {
# 内部步骤列表
steps <- list()
if (do_colnames) steps <- append(steps, list(clean_colnames))
if (do_drop_empty) steps <- append(steps, list(drop_empty))
if (do_fix_types) steps <- append(steps, list(fix_types))
if (do_normalize) steps <- append(steps, list(normalize_strings))
if (do_dedup) steps <- append(steps, list(remove_duplicates))
if (do_impute) steps <- append(steps, list(impute_missing))
# 添加额外步骤
steps <- c(steps, extra_steps)
# 执行 Pipeline
for (f in steps) {
log_step(paste("Running step:", deparse(substitute(f))))
df <- f(df)
}
log_step("Pipeline completed.")
df
}
# ================================
# 4. 使用
# ================================
# df_clean <- clean_pipeline(raw_df)
# 带额外步骤
# df_clean <- clean_pipeline(raw_df, extra_steps = list(
# function(x) mutate(x, new_col = row_number())
# ))
今天搞得头晕目眩的,好累,具体解释找机会吧,今天先结束工作了,各位,下个工作日见!