mcpField
G
geo-database

geo-database

github.com/davila7数据与数据库33.0k350 次安装1 天前更新
代码仓库

关于 geo-database

面向基因表达和功能基因组学研究者的数据技能,介绍 NCBI GEO 数据库的使用。涵盖数据集搜索、获取、批量处理,以及通过 GEOparse、E-utilities 和 FTP 进行分析。

主要功能

  1. 01搜索 GEO 研究与表达谱
  2. 02获取系列和样本数据
  3. 03下载补充文件及原始文件
  4. 04批量查询元数据和数据集
  5. 05分析并比较表达数据
  6. 06使用 GEOparse、E-utilities 和 FTP

适用场景

  1. 01查找疾病或条件相关研究
  2. 02下载转录组研究数据
  3. 03比较不同研究的表达情况
  4. 04探索药物反应或生物标志物

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/davila7/claude-code-templates --skill geo-database

安装后在 Claude Code 中输入/geo-database确认已加载。

附带文件references/geo_reference.md

详细介绍

GEO 数据库

概述

基因表达综合数据库(GEO)是 NCBI 用于存储高通量基因表达和功能基因组学数据的公共资源库。GEO 收录了超过 264,000 项研究,其中包含来自基于芯片和基于测序实验的 800 多万个样本。

何时使用此技能

在搜索基因表达数据集、获取实验数据、下载原始文件和处理后文件、查询表达谱,或将 GEO 数据整合到计算分析工作流中时,应使用此技能。

核心功能

1. 了解 GEO 数据组织方式

GEO 使用不同的登录号类型按层级组织数据:

系列(GSE): 一项包含一组相关样本的完整实验

  • 示例:GSE123456
  • 包含实验设计、样本和整体研究信息
  • GEO 中最大的组织单位
  • 当前数量:264,928+ 个系列

样本(GSM): 单个实验样本或生物学重复

  • 示例:GSM987654
  • 包含单个样本的数据、实验方案和元数据
  • 与平台和系列相关联
  • 当前数量:8,068,632+ 个样本

平台(GPL): 所用的微阵列或测序平台

  • 示例:GPL570(Affymetrix Human Genome U133 Plus 2.0 Array)
  • 描述技术以及探针/特征注释
  • 多项实验共用
  • 当前数量:27,739+ 个平台

数据集(GDS): 格式一致的精选数据集

  • 示例:GDS5678
  • 按研究设计组织、可进行实验比较的样本
  • 已经过差异分析处理
  • GEO 数据的子集(4,348 个精选数据集)
  • 适合快速比较分析

表达谱: 与序列特征相关联的基因特异性表达数据

  • 可按基因名称或注释查询
  • 可交叉引用 Entrez Gene
  • 支持跨所有研究进行以基因为中心的搜索
2. 搜索 GEO 数据

GEO 数据集搜索:

按关键词、生物体或实验条件搜索研究:

from Bio import Entrez

# Configure Entrez (required)
Entrez.email = "[email protected]"

# Search for datasets
def search_geo_datasets(query, retmax=20):
    """Search GEO DataSets database"""
    handle = Entrez.esearch(
        db="gds",
        term=query,
        retmax=retmax,
        usehistory="y"
    )
    results = Entrez.read(handle)
    handle.close()
    return results

# Example searches
results = search_geo_datasets("breast cancer[MeSH] AND Homo sapiens[Organism]")
print(f"Found {results['Count']} datasets")

# Search by specific platform
results = search_geo_datasets("GPL570[Accession]")

# Search by study type
results = search_geo_datasets("expression profiling by array[DataSet Type]")

GEO 表达谱搜索:

查找基因特异性表达模式:

# Search for gene expression profiles
def search_geo_profiles(gene_name, organism="Homo sapiens", retmax=100):
    """Search GEO Profiles for a specific gene"""
    query = f"{gene_name}[Gene Name] AND {organism}[Organism]"
    handle = Entrez.esearch(
        db="geoprofiles",
        term=query,
        retmax=retmax
    )
    results = Entrez.read(handle)
    handle.close()
    return results

# Find TP53 expression across studies
tp53_results = search_geo_profiles("TP53", organism="Homo sapiens")
print(f"Found {tp53_results['Count']} expression profiles for TP53")

高级搜索模式:

# Combine multiple search terms
def advanced_geo_search(terms, operator="AND"):
    """Build complex search queries"""
    query = f" {operator} ".join(terms)
    return search_geo_datasets(query)

# Find recent high-throughput studies
search_terms = [
    "RNA-seq[DataSet Type]",
    "Homo sapiens[Organism]",
    "2024[Publication Date]"
]
results = advanced_geo_search(search_terms)

# Search by author and condition
search_terms = [
    "Smith[Author]",
    "diabetes[Disease]"
]
results = advanced_geo_search(search_terms)
3. 使用 GEOparse 获取 GEO 数据(推荐)

GEOparse 是用于访问 GEO 数据的主要 Python 库:

安装:

uv pip install GEOparse

基本用法:

import GEOparse

# Download and parse a GEO Series
gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")

# Access series metadata
print(gse.metadata['title'])
print(gse.metadata['summary'])
print(gse.metadata['overall_design'])

# Access sample information
for gsm_name, gsm in gse.gsms.items():
    print(f"Sample: {gsm_name}")
    print(f"  Title: {gsm.metadata['title'][0]}")
    print(f"  Source: {gsm.metadata['source_name_ch1'][0]}")
    print(f"  Characteristics: {gsm.metadata.get('characteristics_ch1', [])}")

# Access platform information
for gpl_name, gpl in gse.gpls.items():
    print(f"Platform: {gpl_name}")
    print(f"  Title: {gpl.metadata['title'][0]}")
    print(f"  Organism: {gpl.metadata['organism'][0]}")

处理表达数据:

import GEOparse
import pandas as pd

# Get expression data from series
gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")

# Extract expression matrix
# Method 1: From series matrix file (fastest)
if hasattr(gse, 'pivot_samples'):
    expression_df = gse.pivot_samples('VALUE')
    print(expression_df.shape)  # genes x samples

# Method 2: From individual samples
expression_data = {}
for gsm_name, gsm in gse.gsms.items():
    if hasattr(gsm, 'table'):
        expression_data[gsm_name] = gsm.table['VALUE']

expression_df = pd.DataFrame(expression_data)
print(f"Expression matrix: {expression_df.shape}")

访问补充文件:

import GEOparse

gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")

# Download supplementary files
gse.download_supplementary_files(
    directory="./data/GSE123456_suppl",
    download_sra=False  # Set to True to download SRA files
)

# List available supplementary files
for gsm_name, gsm in gse.gsms.items():
    if hasattr(gsm, 'supplementary_files'):
        print(f"Sample {gsm_name}:")
        for file_url in gsm.metadata.get('supplementary_file', []):
            print(f"  {file_url}")

筛选和提取子集数据:

import GEOparse

gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")

# Filter samples by metadata
control_samples = [
    gsm_name for gsm_name, gsm in gse.gsms.items()
    if 'control' in gsm.metadata.get('title', [''])[0].lower()
]

treatment_samples = [
    gsm_name for gsm_name, gsm in gse.gsms.items()
    if 'treatment' in gsm.metadata.get('title', [''])[0].lower()
]

print(f"Control samples: {len(control_samples)}")
print(f"Treatment samples: {len(treatment_samples)}")

# Extract subset expression matrix
expression_df = gse.pivot_samples('VALUE')
control_expr = expression_df[control_samples]
treatment_expr = expression_df[treatment_samples]
4. 使用 NCBI E-utilities 访问 GEO

E-utilities 提供对 GEO 元数据的底层编程访问:

E-utilities 基本工作流:

from Bio import Entrez
import time

Entrez.email = "[email protected]"

# Step 1: Search for GEO entries
def search_geo(query, db="gds", retmax=100):
    """Search GEO using E-utilities"""
    handle = Entrez.esearch(
        db=db,
        term=query,
        retmax=retmax,
        usehistory="y"
    )
    results = Entrez.read(handle)
    handle.close()
    return results

# Step 2: Fetch summaries
def fetch_geo_summaries(id_list, db="gds"):
    """Fetch document summaries for GEO entries"""
    ids = ",".join(id_list)
    handle = Entrez.esummary(db=db, id=ids)
    summaries = Entrez.read(handle)
    handle.close()
    return summaries

# Step 3: Fetch full records
def fetch_geo_records(id_list, db="gds"):
    """Fetch full GEO records"""
    ids = ",".join(id_list)
    handle = Entrez.efetch(db=db, id=ids, retmode="xml")
    records = Entrez.read(handle)
    handle.close()
    return records

# Example workflow
search_results = search_geo("breast cancer AND Homo sapiens")
id_list = search_results['IdList'][:5]

summaries = fetch_geo_summaries(id_list)
for summary in summaries:
    print(f"GDS: {summary.get('Accession', 'N/A')}")
    print(f"Title: {summary.get('title', 'N/A')}")
    print(f"Samples: {summary.get('n_samples', 'N/A')}")
    print()

使用 E-utilities 进行批量处理:

from Bio import Entrez
import time

Entrez.email = "[email protected]"

def batch_fetch_geo_metadata(accessions, batch_size=100):
    """Fetch metadata for multiple GEO accessions"""
    results = {}

    for i in range(0, len(accessions), batch_size):
        batch = accessions[i:i + batch_size]

        # Search for each accession
        for accession in batch:
            try:
                query = f"{accession}[Accession]"
                search_handle = Entrez.esearch(db="gds", term=query)
                search_results = Entrez.read(search_handle)
                search_handle.close()

                if search_results['IdList']:
                    # Fetch summary
                    summary_handle = Entrez.esummary(
                        db="gds",
                        id=search_results['IdList'][0]
                    )
                    summary = Entrez.read(summary_handle)
                    summary_handle.close()
                    results[accession] = summary[0]

                # Be polite to NCBI servers
                time.sleep(0.34)  # Max 3 requests per second

            except Exception as e:
                print(f"Error fetching {accession}: {e}")

    return results

# Fetch metadata for multiple datasets
gse_list = ["GSE100001", "GSE100002", "GSE100003"]
metadata = batch_fetch_geo_metadata(gse_list)
5. 通过 FTP 直接访问数据文件

GEO 数据的 FTP URL:

可通过 FTP 直接下载 GEO 数据:

import ftplib
import os

def download_geo_ftp(accession, file_type="matrix", dest_dir="./data"):
    """Download GEO files via FTP"""
    # Construct FTP path based on accession type
    if accession.startswith("GSE"):
        # Series files
        gse_num = accession[3:]
        base_num = gse_num[:-3] + "nnn"
        ftp_path = f"/geo/series/GSE{base_num}/{accession}/"

        if file_type == "matrix":
            filename = f"{accession}_series_matrix.txt.gz"
        elif file_type == "soft":
            filename = f"{accession}_family.soft.gz"
        elif file_type == "miniml":
            filename = f"{accession}_family.xml.tgz"

    # Connect to FTP server
    ftp = ftplib.FTP("ftp.ncbi.nlm.nih.gov")
    ftp.login()
    ftp.cwd(ftp_path)

    # Download file
    os.makedirs(dest_dir, exist_ok=True)
    local_file = os.path.join(dest_dir, filename)

    with open(local_file, 'wb') as f:
        ftp.retrbinary(f'RETR {filename}', f.write)

    ftp.quit()
    print(f"Downloaded: {local_file}")
    return local_file

# Download series matrix file
download_geo_ftp("GSE123456", file_type="matrix")

# Download SOFT format file
download_geo_ftp("GSE123456", file_type="soft")

使用 wget 或 curl 下载:

# Download series matrix file
wget ftp://ftp.ncbi.nlm.nih.gov/geo/series/GSE123nnn/GSE123456/matrix/GSE123456_series_matrix.txt.gz

# Download all supplementary files for a series
wget -r -np -nd ftp://ftp.ncbi.nlm.nih.gov/geo/series/GSE123nnn/GSE123456/suppl/

# Download SOFT format family file
wget ftp://ftp.ncbi.nlm.nih.gov/geo/series/GSE123nnn/GSE123456/soft/GSE123456_family.soft.gz
6. 分析 GEO 数据

质量控制和预处理:

import GEOparse
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Load dataset
gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")
expression_df = gse.pivot_samples('VALUE')

# Check for missing values
print(f"Missing values: {expression_df.isnull().sum().sum()}")

# Log transformation (if needed)
if expression_df.min().min() > 0:  # Check if already log-transformed
    if expression_df.max().max() > 100:
        expression_df = np.log2(expression_df + 1)
        print("Applied log2 transformation")

# Distribution plots
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
expression_df.plot.box(ax=plt.gca())
plt.title("Expression Distribution per Sample")
plt.xticks(rotation=90)

plt.subplot(1, 2, 2)
expression_df.mean(axis=1).hist(bins=50)
plt.title("Gene Expression Distribution")
plt.xlabel("Average Expression")

plt.tight_layout()
plt.savefig("geo_qc.png", dpi=300, bbox_inches='tight')

差异表达分析:

import GEOparse
import pandas as pd
import numpy as np
from scipy import stats

gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")
expression_df = gse.pivot_samples('VALUE')

# Define sample groups
control_samples = ["GSM1", "GSM2", "GSM3"]
treatment_samples = ["GSM4", "GSM5", "GSM6"]

# Calculate fold changes and p-values
results = []
for gene in expression_df.index:
    control_expr = expression_df.loc[gene, control_samples]
    treatment_expr = expression_df.loc[gene, treatment_samples]

    # Calculate statistics
    fold_change = treatment_expr.mean() - control_expr.mean()
    t_stat, p_value = stats.ttest_ind(treatment_expr, control_expr)

    results.append({
        'gene': gene,
        'log2_fold_change': fold_change,
        'p_value': p_value,
        'control_mean': control_expr.mean(),
        'treatment_mean': treatment_expr.mean()
    })

# Create results DataFrame
de_results = pd.DataFrame(results)

# Multiple testing correction (Benjamini-Hochberg)
from statsmodels.stats.multitest import multipletests
_, de_results['q_value'], _, _ = multipletests(
    de_results['p_value'],
    method='fdr_bh'
)

# Filter significant genes
significant_genes = de_results[
    (de_results['q_value'] < 0.05) &
    (abs(de_results['log2_fold_change']) > 1)
]

print(f"Significant genes: {len(significant_genes)}")
significant_genes.to_csv("de_results.csv", index=False)

相关性和聚类分析:

import GEOparse
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.cluster import hierarchy
from scipy.spatial.distance import pdist

gse = GEOparse.get_GEO(geo="GSE123456", destdir="./data")
expression_df = gse.pivot_samples('VALUE')

# Sample correlation heatmap
sample_corr = expression_df.corr()

plt.figure(figsize=(10, 8))
sns.heatmap(sample_corr, cmap='coolwarm', center=0,
            square=True, linewidths=0.5)
plt.title("Sample Correlation Matrix")
plt.tight_layout()
plt.savefig("sample_correlation.png", dpi=300, bbox_inches='tight')

# Hierarchical clustering
distances = pdist(expression_df.T, metric='correlation')
linkage = hierarchy.linkage(distances, method='average')

plt.figure(figsize=(12, 6))
hierarchy.dendrogram(linkage, labels=expression_df.columns)
plt.title("Hierarchical Clustering of Samples")
plt.xlabel("Samples")
plt.ylabel("Distance")
plt.xticks(rotation=90)
plt.tight_layout()
plt.savefig("sample_clustering.png", dpi=300, bbox_inches='tight')
7. 批量处理多个数据集

下载并处理多个系列:

import GEOparse
import pandas as pd
import os

def batch_download_geo(gse_list, destdir="./geo_data"):
    """Download multiple GEO series"""
    results = {}

    for gse_id in gse_list:
        try:
            print(f"Processing {gse_id}...")
            gse = GEOparse.get_GEO(geo=gse_id, destdir=destdir)

            # Extract key information
            results[gse_id] = {
                'title': gse.metadata.get('title', ['N/A'])[0],
                'organism': gse.metadata.get('organism', ['N/A'])[0],
                'platform': list(gse.gpls.keys())[0] if gse.gpls else 'N/A',
                'num_samples': len(gse.gsms),
                'submission_date': gse.metadata.get('submission_date', ['N/A'])[0]
            }

            # Save expression data
            if hasattr(gse, 'pivot_samples'):
                expr_df = gse.pivot_samples('VALUE')
                expr_df.to_csv(f"{destdir}/{gse_id}_expression.csv")
                results[gse_id]['num_genes'] = len(expr_df)

        except Exception as e:
            print(f"Error processing {gse_id}: {e}")
            results[gse_id] = {'error': str(e)}

    # Save summary
    summary_df = pd.DataFrame(results).T
    summary_df.to_csv(f"{destdir}/batch_summary.csv")

    return results

# Process multiple datasets
gse_list = ["GSE100001", "GSE100002", "GSE100003"]
results = batch_download_geo(gse_list)

跨研究进行荟萃分析:

import GEOparse
import pandas as pd
import numpy as np

def meta_analysis_geo(gse_list, gene_of_interest):
    """Perform meta-analysis of gene expression across studies"""
    results = []

    for gse_id in gse_list:
        try:
            gse = GEOparse.get_GEO(geo=gse_id, destdir="./data")

            # Get platform annotation
            gpl = list(gse.gpls.values())[0]

            # Find gene in platform
            if hasattr(gpl, 'table'):
                gene_probes = gpl.table[
                    gpl.table['Gene Symbol'].str.contains(
                        gene_of_interest,
                        case=False,
                        na=False
                    )
                ]

                if not gene_probes.empty:
                    expr_df = gse.pivot_samples('VALUE')

                    for probe_id in gene_probes['ID']:
                        if probe_id in expr_df.index:
                            expr_values = expr_df.loc[probe_id]

                            results.append({
                                'study': gse_id,
                                'probe': probe_id,
                                'mean_expression': expr_values.mean(),
                                'std_expression': expr_values.std(),
                                'num_samples': len(expr_values)
                            })

        except Exception as e:
            print(f"Error in {gse_id}: {e}")

    return pd.DataFrame(results)

# Meta-analysis for TP53
gse_studies = ["GSE100001", "GSE100002", "GSE100003"]
meta_results = meta_analysis_geo(gse_studies, "TP53")
print(meta_results)

安装和设置

Python 库
# Primary GEO access library (recommended)
uv pip install GEOparse

# For E-utilities and programmatic NCBI access
uv pip install biopython

# For data analysis
uv pip install pandas numpy scipy

# For visualization
uv pip install matplotlib seaborn

# For statistical analysis
uv pip install statsmodels scikit-learn
配置

设置 NCBI E-utilities 访问:

from Bio import Entrez

# Always set your email (required by NCBI)
Entrez.email = "[email protected]"

# Optional: Set API key for increased rate limits
# Get your API key from: https://www.ncbi.nlm.nih.gov/account/
Entrez.api_key = "your_api_key_here"

# With API key: 10 requests/second
# Without API key: 3 requests/second

常见用例

转录组学研究
  • 下载特定条件下的基因表达数据
  • 比较不同研究中的表达谱
  • 识别差异表达基因
  • 对多个数据集进行荟萃分析
药物反应研究
  • 分析药物处理后的基因表达变化
  • 识别药物反应生物标志物
  • 比较药物在不同细胞系或患者中的作用
  • 构建药物敏感性的预测模型
疾病生物学
  • 研究疾病组织与正常组织中的基因表达
  • 识别疾病相关表达特征
  • 比较患者亚组和疾病阶段
  • 分析表达与临床结局的相关性
生物标志物发现
  • 筛选诊断或预后标志物
  • 在独立队列中验证生物标志物
  • 比较标志物在不同平台上的表现
  • 整合表达数据与临床数据

核心概念

SOFT(Simple Omnibus Format in Text): GEO 的主要文本格式,包含元数据和数据表。可使用 GEOparse 轻松解析。

MINiML(MIAME Notation in Markup Language): GEO 数据的 XML 格式,用于程序化访问和数据交换。

系列矩阵(Series Matrix): 以制表符分隔的表达矩阵,样本为列,基因为行,探针为行。获取表达数据最快捷的格式。

MIAME 合规性: 微阵列实验最低信息要求(Minimum Information About a Microarray Experiment)——GEO 对所有提交数据强制要求的标准化注释。

表达值类型: 不同类型的表达测量值(原始信号、归一化值、对数转换值)。务必检查平台和处理方法。

平台注释: 将探针/特征 ID 映射到基因。对于表达数据的生物学解读至关重要。

GEO2R 网页工具

如需快速分析且无需编写代码,可使用 GEO2R:

速率限制和最佳实践

NCBI E-utilities 速率限制:

  • 不使用 API 密钥:每秒 3 次请求
  • 使用 API 密钥:每秒 10 次请求
  • 在请求之间加入延迟:time.sleep(0.34)(不使用 API 密钥)或 time.sleep(0.1)(使用 API 密钥)

FTP 访问:

  • FTP 下载没有速率限制
  • 批量下载的首选方式
  • 可使用 wget -r 下载整个目录

GEOparse 缓存:

  • GEOparse 会自动将下载的文件缓存到 destdir
  • 后续调用会使用缓存数据
  • 定期清理缓存以节省磁盘空间

最佳实践:

  • 使用 GEOparse 访问系列级数据(最简单)
  • 使用 E-utilities 搜索元数据并执行批量查询
  • 使用 FTP 直接下载文件并执行批量操作
  • 在本地缓存数据,避免重复下载
  • 使用 Biopython 时,务必设置 Entrez.email

资源

references/geo_reference.md

全面的参考文档,涵盖:

  • E-utilities API 规范和端点的详细说明
  • SOFT 和 MINiML 文件格式的完整文档
  • GEOparse 高级用法模式和示例
  • FTP 目录结构和文件命名约定
  • 数据处理流程和归一化方法
  • 常见问题排查和错误处理
  • 特定平台的注意事项和特性

如需深入了解技术细节、复杂查询模式或处理不常见的数据格式,请参阅此参考文档。

重要说明

数据质量注意事项
  • GEO 接受用户提交的数据,质量标准各不相同
  • 务必检查平台注释和处理方法
  • 核实样本元数据和实验设计
  • 谨慎处理不同研究之间的批次效应
  • 考虑重新处理原始数据以确保一致性
文件大小警告
  • 系列矩阵文件可能很大(大型研究的文件可超过 1 GB)
  • 补充文件(例如 CEL 文件)可能非常大
  • 下载前请预留充足的磁盘空间
  • 可考虑分批下载样本
数据使用和引用
  • GEO 数据可免费用于研究
  • 使用 GEO 数据时,务必引用原始研究
  • 引用 GEO 数据库:Barrett 等人(2013),Nucleic Acids Research
  • 检查各数据集是否有使用限制
  • 遵循 NCBI 的程序化访问指南
常见陷阱
  • 不同平台使用不同的探针 ID(需要注释映射)
  • 表达值可能是原始值、标准化值或经过对数转换的值(请检查元数据)
  • 不同研究的样本元数据格式可能不一致
  • 并非所有系列都有系列矩阵文件(较早提交的数据)
  • 平台注释可能已过时(基因已更名、ID 已弃用)

其他资源

评论

支持 Markdown