一文搞定GEO数据分析:从下载到生存分析前处理全流程(手把手教程)
GEO数据库下载与表达矩阵处理全流程;以GSE26942为例
前言
GEO(Gene Expression Omnibus)是 NCBI 维护的基因表达数据库,收录了海量公开的芯片和测序数据。
本文以 GSE26942(胃癌相关数据集)为例,手把手演示如何用 R 语言完成数据的下载与预处理。
第一步:下载 GEO 数据
使用 GEOquery 包可以一行代码完成数据下载,若本地已存在文件则自动读取,无需重复下载。
# 如未安装,先运行下面两行# BiocManager::install("GEOquery")# install.packages("stringr")library(GEOquery)library(stringr)setwd('./GEO_data')gset <- getGEO("GSE26942", destdir = ".", AnnotGPL = FALSE, getGPL = FALSE)#本地读取技巧:若已手动下载 GSE26942_series_matrix.txt.gz,可直接用gset <- getGEO(filename = "GSE26942_series_matrix.txt.gz",AnnotGPL = F, destdir = "./",getGPL=F)
第二步:提取表达矩阵 & 判断是否需要 log 转换
芯片数据常见两种形态:原始强度值(通常 > 100) 和已 log 转换值(分布在 0~15 左右)。直接用分位数判断,避免二次 log 导致数据失真。
dat <- exprs(gset)ex <- datqx <- as.numeric(quantile(ex, c(0,.25,.5,.75,.99,1), na.rm=TRUE))LogC <- (qx[5] > 100) || (qx[6] - qx[1] > 50 && qx[2] > 0) || (qx[2] > 0 && qx[2] < 1 && qx[4] > 1 && qx[4] < 2)if (LogC) { ex[which(ex <= 0)] <- NA dat <- log2(ex) cat("✓ log2 转换完成\n")} else { cat("✓ 数据已转换,无需处理\n")}
第三步:探针 ID → 基因 Symbol 注释
芯片数据以探针ID为行名,必须借助 GPL 平台注释文件将其转换为基因 Symbol,才能与其他数据集对接分析。
GPL 文件下载地址:进入 https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GPL6947,页面底部找到 “Full Table” 下载 .txt 文件,文件名类似 GPL6947-XXXXX.txt
读取 GPL 注释文件并提取 Symbolgpl <- read.table("GPL6947-13512.txt", header = TRUE, fill = TRUE, sep = "\t", comment.char = "#", quote = "")ids <- gpl[, c("ID", "Symbol")]colnames(ids) <- c('probe_id', 'symbol')# 提取 Symbol(部分平台用 "///" 分隔多字段)ids$symbol <- trimws(str_split(ids$symbol, '///', simplify=TRUE)[,1])# 过滤无注释探针ids <- ids[ids$symbol != '' & ids$symbol != '---', ]
第四步:多探针取最大值(或均值)去重
一个基因可能对应多个探针,常见处理策略有两种,选其一即可:
|
|
|
|---|---|
aggregate(. ~ symbol, max) |
|
aggregate(. ~ symbol, mean) |
|
# 过滤 + 合并ids <- ids[ids$probe_id %in% rownames(dat), ]dat <- dat[ids$probe_id, ]dat <- cbind(ids, dat)# 去重:取每个基因表达量最大的探针dat <- aggregate(. ~ symbol, data = dat, max)# 整理行名,去掉辅助列rownames(dat) <- dat[, 1]dat <- dat[, -c(1, 2)]
第五步:导出最终矩阵
final_data <- data.frame(ID = rownames(dat), dat)write.table(final_data, file = "GSE26942_expr.txt", sep = "\t", quote = FALSE, row.names = FALSE)

第六步:提取临床信息
用 pData() 提取样本的临床信息,先用 colnames() 看一下有哪些字段,然后导出为CSV文件备用。
pd <- pData(gset)colnames(pd)write.csv(pd, 'clinical_GSE26942.csv', row.names = TRUE)

第七步:不包含完整信息
这个数据集有个特殊情况:GEO页面上存的临床信息不包含完整的生存数据,需要去读文章的补充材料。
对应的文章发表在 Nature Communications,补充表格就是这个xlsx文件: 这里用patient ID作为关联键,把两个表合并,然后重命名为我们熟悉的 OS 和 OS.time,这样后续做生存分析就可以直接用了。
dat_surv <- read_excel("41467_2018_4179_MOESM5_ESM.xlsx")pd <- pd %>% rownames_to_column("ID") %>% rename(Patients_ID = `patient:ch1`) %>% select(ID, Patients_ID)pd1 <- merge(pd, dat_surv, by = 'Patients_ID')pd1 <- pd1 %>% rename(OS = `Death (1=yes, 0=no)`, OS.time = `OS.m`) %>% select(ID, OS, OS.time)write.csv(pd1,file = "cli_GSE26942.csv",row.names = F)

六、小结
本流程以 GSE26942 为例,系统梳理了 GEO 数据从下载、表达矩阵处理到临床信息整合的完整分析步骤。
核心思路是:数据获取 → 标准化处理 → 注释转换 → 去重整合 → 临床匹配 → 输出可分析矩阵
🔔 本文数据及完整代码已整理好,关注公众号后私信回复「GEO数据处理下载」即可免费领取,觉得有帮助欢迎转发分享 🌱


夜雨聆风