mcpField
G
geo-database

geo-database

github.com/jaechang-hitsデータ・データベース38437 回インストール1 週間前に更新
リポジトリ

geo-database について

geo-databaseは、NCBI GEOの公開機能ゲノミクス記録を検索、ダウンロード、解析するスキルです。GEOparseとNCBI E-utilitiesを使い、GEOシリーズ、発現データ、サンプルメタデータを取得できます。

主な機能

  1. 01E-utilitiesによるGEO記録の検索
  2. 02GSE・GPL・GSM記録のダウンロードと解析
  3. 03発現行列とサンプルメタデータの抽出
  4. 04プラットフォームのプローブと遺伝子注釈の対応付け
  5. 05FTPから大型シリーズ行列ファイルを取得

活用シーン

  1. 01生物種・組織・条件で研究を検索
  2. 02差次的発現解析用のGEO発現データを準備
  3. 03メタ解析用のサンプル注釈を収集

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill geo-database

インストール後、Claude Code で/geo-databaseを入力して読み込まれたか確認します。

詳細

GEO Gene Expression Omnibus データベース

概要

GEO(Gene Expression Omnibus)は、NCBI が公開するハイスループット機能ゲノミクスデータのリポジトリです。マイクロアレイ、RNA-seq、ChIP-seq、メチル化、プロテオミクスの実験から得られた 200,000 件以上のデータセット(シリーズ)が含まれています。GEOparse は、GEO レコード(GSE シリーズ、GPL プラットフォーム、GSM サンプル)をダウンロードして解析するための Python インターフェースを提供し、NCBI E-utilities を使うと GEO のメタデータをプログラムから検索できます。

使用する場面

  • 生物種、組織、疾患、実験条件を指定して、公開されている遺伝子発現データセットを検索する
  • 特定の GEO シリーズ(GSE)と、その発現マトリックスおよびサンプルのメタデータをダウンロードして解析する
  • メタ解析に使うサンプルアノテーションテーブル(治療群、臨床共変量など)を抽出する
  • マイクロアレイの発現データ(GPL プラットフォームでアノテーションされたプローブ)を整然とした DataFrame に読み込む
  • 対象の遺伝子や経路に関連する GEO 実験をすべて取得する
  • 下流解析に向けて GEO データセットをダウンロード・処理する自動化パイプラインを構築する
  • 大規模なシングルセル RNA-seq データには cellxgene-census を使用します。アラインメント済みリードには、代わりに ENA/SRA から FASTQ をダウンロードしてください

前提条件

  • Python パッケージ:GEOparse、requests、pandas
  • データ要件:GSE/GPL/GSM アクセッション番号、または検索語
  • 環境:インターネット接続、ダウンロード先のローカルディレクトリへの書き込み権限
  • レート制限:E-utilities は認証なしで 3 req/s、API キー使用時は 10 req/s。GEO FTP は無制限です
pip install GEOparse requests pandas

クイックスタート

import GEOparse

# Download a GEO series (caches in current directory)
gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/")
print(f"Title: {gse.metadata['title'][0]}")
print(f"Samples: {len(gse.gsms)}")
print(f"Platform: {list(gse.gpls.keys())}")

# Sample metadata
meta = gse.phenotype_data
print(meta.head())

コア API

クエリ 1:E-utilities で GEO データセットを検索する

キーワード、生物種、またはデータセットの種類で GEO シリーズ(GSE)を検索します。

import requests

EMAIL = "[email protected]"
BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"

def geo_search(query, retmax=20):
    r = requests.get(f"{BASE}/esearch.fcgi",
                     params={"db": "gds", "term": query,
                             "retmax": retmax, "retmode": "json", "email": EMAIL})
    r.raise_for_status()
    return r.json()["esearchresult"]

# Search for human breast cancer RNA-seq datasets
result = geo_search(
    "breast cancer[title] AND Homo sapiens[organism] AND gse[entry type]",
    retmax=10
)
print(f"Found {result['count']} matching GEO datasets")
print(f"First accessions (UIDs): {result['idlist']}")
# Search for specific platform (e.g., Illumina HumanHT-12)
result = geo_search(
    "Illumina HumanHT-12[platform] AND Homo sapiens[organism] AND gse[entry type]",
    retmax=5
)
print(f"Illumina HumanHT-12 human datasets: {result['count']}")
クエリ 2:データセットの概要メタデータを取得する

検索結果のタイトル、アクセッション、生物種を取得します。

import requests

EMAIL = "[email protected]"
BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"

def geo_summary(uids):
    r = requests.post(f"{BASE}/esummary.fcgi",
                      data={"db": "gds", "id": ",".join(uids),
                            "retmode": "json", "email": EMAIL})
    r.raise_for_status()
    return r.json()["result"]

# Get metadata for search results
result = geo_search_func = lambda q: requests.get(
    f"{BASE}/esearch.fcgi",
    params={"db": "gds", "term": q, "retmax": 3, "retmode": "json", "email": EMAIL}
).json()["esearchresult"]["idlist"]

uids = requests.get(
    f"{BASE}/esearch.fcgi",
    params={"db": "gds", "term": "lung cancer[title] AND gse[entry type]",
            "retmax": 3, "retmode": "json", "email": EMAIL}
).json()["esearchresult"]["idlist"]

summaries = geo_summary(uids)
for uid in summaries.get("uids", []):
    s = summaries[uid]
    print(f"\nAccession: {s.get('accession')} | {s.get('title')}")
    print(f"  Organism: {s.get('taxon')}")
    print(f"  Samples: {s.get('n_samples')}")
    print(f"  Type: {s.get('gdstype')}")
クエリ 3:GEO シリーズをダウンロードして解析する

GEOparse を使って、発現マトリックスとサンプルのメタデータを含む GSE レコード全体をダウンロードします。

import GEOparse

# Download GSE (auto-caches; skip download if already present)
gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/", silent=True)

# Series metadata
print(f"Title   : {gse.metadata['title'][0]}")
print(f"Summary : {gse.metadata['summary'][0][:200]}...")
print(f"Samples : {len(gse.gsms)} GSMs")
print(f"Platforms: {list(gse.gpls.keys())}")
# Sample metadata table (phenotype data)
meta = gse.phenotype_data
print(f"Metadata columns: {list(meta.columns)}")
print(meta.head())
クエリ 4:発現マトリックスを抽出する

プローブレベルの発現データを解析し、必要に応じてプラットフォームの遺伝子アノテーションと結合します。

import GEOparse, pandas as pd

gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/", silent=True)

# Pivot to gene expression matrix (probes × samples)
gpl_id = list(gse.gpls.keys())[0]
pivot = gse.pivot_samples("VALUE", gpl_id)
print(f"Expression matrix shape: {pivot.shape}")  # (probes, samples)
print(pivot.iloc[:5, :3])
# Annotate probes with gene symbols from the GPL platform
gpl = gse.gpls[gpl_id]
annot = gpl.table[["ID", "Gene Symbol", "Gene Title"]].copy()
annot.columns = ["ID", "gene_symbol", "gene_title"]
annot = annot.dropna(subset=["gene_symbol"])
annot = annot[annot["gene_symbol"] != ""]

expr_annotated = pivot.join(annot.set_index("ID"), how="inner")
print(f"Annotated expression matrix: {expr_annotated.shape}")
print(expr_annotated[["gene_symbol", "gene_title"]].head())
クエリ 5:個別サンプル(GSM)をダウンロードする

単一サンプルの発現値とメタデータを取得します。

import GEOparse

gsm = GEOparse.get_GEO("GSM45553", destdir="./geo_data/", silent=True)

print(f"Title   : {gsm.metadata['title'][0]}")
print(f"Source  : {gsm.metadata.get('source_name_ch1', ['n/a'])[0]}")
print(f"Organism: {gsm.metadata.get('organism_ch1', ['n/a'])[0]}")
print(f"Data rows: {len(gsm.table)}")
print(gsm.table.head())
クエリ 6:大規模シリーズを FTP から直接ダウンロードする

大規模なデータセットの場合、シリーズマトリックスファイルを GEO FTP から直接ダウンロードします。

import urllib.request, gzip, io, pandas as pd

# GEO series matrix file URL pattern
accession = "GSE2553"
series_num = accession[3:]  # strip "GSE"
folder = f"GSE{series_num[:-3]}nnn" if len(series_num) > 3 else f"GSE{series_num[:-2]}nn"

url = f"https://ftp.ncbi.nlm.nih.gov/geo/series/{folder}/{accession}/matrix/{accession}_series_matrix.txt.gz"

with urllib.request.urlopen(url) as resp:
    with gzip.open(resp, "rt", encoding="utf-8") as f:
        lines = f.readlines()

# Find metadata lines (start with !) and data table
meta_lines = [l for l in lines if l.startswith("!")]
data_start = next(i for i, l in enumerate(lines) if l.startswith('"ID_REF"'))
df = pd.read_csv(
    io.StringIO("".join(lines[data_start:])),
    sep="\t", index_col=0
)
print(f"Matrix shape: {df.shape}")
print(df.iloc[:3, :3])

主な概念

GEO レコードの種類
  • GSE(シリーズ):すべてのサンプルとメタデータを含む完全な実験
  • GPL(プラットフォーム):マイクロアレイまたはシーケンシングのプラットフォーム定義(プローブ/遺伝子マッピング)
  • GSM(サンプル):単一のハイブリダイゼーションまたはシーケンシング実行
  • GDS(データセット):シリーズのキュレーション済み正規化サブセット(GSE レコードより少数)
SuperSeries と SubSeries

複数のアッセイまたはバッチを含む登録(RNA-seq と ATAC-seq の組み合わせなど)は、1 つ以上の SubSeries GSE を参照する SuperSeries GSE として整理されます。各 SubSeries は独自のサンプル、プラットフォーム、マトリックスを持ちますが、SuperSeries 自体にはサンプルがありません。どちらも gse.metadata で識別できます。

  • SuperSeries:gse.metadata["relation"] に "SuperSeries of: GSExxxx" のようなエントリーが含まれます
  • SubSeries:gse.metadata["relation"] に "SubSeries of: GSEyyyy" が含まれます

発現マトリックスを取得する前に、必ず SubSeries を特定してください。SuperSeries のみをダウンロードすると、メタデータは取得できますが、データは取得できません。

import GEOparse

gse = GEOparse.get_GEO("GSE47966", destdir="./geo_data/", silent=True)  # a SuperSeries
relations = gse.metadata.get("relation", [])
subseries = [r.split(": ")[1] for r in relations if r.startswith("SuperSeries of")]
print(f"SubSeries to download: {subseries}")

for acc in subseries:
    sub = GEOparse.get_GEO(acc, destdir="./geo_data/", silent=True)
    print(f"  {acc}: {len(sub.gsms)} samples, platforms={list(sub.gpls.keys())}")
SOFT 形式と MiniML 形式

GEOparse は SOFT 形式(プレーンテキスト)のファイルをダウンロードします。XML ベースでアクセスするには、E-utilities 経由で MiniML 形式を使用します。発現データには、シリーズマトリックスファイル(タブ区切り)が最もコンパクトな形式です。

一般的なワークフロー

ワークフロー 1:発現データをダウンロードして DE 解析用に準備する

目的:GEO データセットをダウンロードし、発現マトリックスとグループラベルを抽出して、下流の差次的発現解析用に保存します。

import GEOparse, pandas as pd

# Download series
gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/", silent=True)

# 1. Extract expression matrix
gpl_id = list(gse.gpls.keys())[0]
expr = gse.pivot_samples("VALUE", gpl_id)

# 2. Extract sample groups from characteristics
meta = gse.phenotype_data
print("Available metadata columns:", list(meta.columns))

# 3. Annotate probes with gene symbols
gpl = gse.gpls[gpl_id]
gene_col = "Gene Symbol" if "Gene Symbol" in gpl.table.columns else gpl.table.columns[1]
annot = gpl.table[["ID", gene_col]].dropna()
annot.columns = ["probe_id", "gene_symbol"]
annot = annot[annot["gene_symbol"].str.strip() != ""]

expr_genes = expr.join(annot.set_index("probe_id")[["gene_symbol"]], how="inner")
expr_genes = expr_genes.groupby("gene_symbol").mean()  # average duplicate probes

print(f"Genes × Samples: {expr_genes.shape}")
expr_genes.to_csv("expression_matrix.csv")
meta.to_csv("sample_metadata.csv")
print("Saved: expression_matrix.csv, sample_metadata.csv")
ワークフロー 2:検索してデータセットの一覧を作成する

目的:GEO でトピックに合致する研究を検索し、キュレーション済みの一覧を CSV 形式で作成します。

import requests, time, pandas as pd

EMAIL = "[email protected]"
BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"

topic = "Alzheimer disease"
r = requests.get(f"{BASE}/esearch.fcgi",
                 params={"db": "gds", "email": EMAIL, "retmode": "json", "retmax": 50,
                         "term": f"{topic}[title] AND Homo sapiens[organism] AND gse[entry type]"})
uids = r.json()["esearchresult"]["idlist"]
print(f"Found {len(uids)} GSE datasets for '{topic}'")

rows = []
for i in range(0, len(uids), 20):
    batch = uids[i:i+20]
    r2 = requests.post(f"{BASE}/esummary.fcgi",
                       data={"db": "gds", "id": ",".join(batch),
                             "retmode": "json", "email": EMAIL})
    result = r2.json()["result"]
    for uid in result.get("uids", []):
        s = result[uid]
        rows.append({
            "accession": s.get("accession"),
            "title": s.get("title"),
            "n_samples": s.get("n_samples"),
            "organism": s.get("taxon"),
            "gds_type": s.get("gdstype"),
            "pub_date": s.get("pdat"),
        })
    time.sleep(0.4)

df = pd.DataFrame(rows).sort_values("n_samples", ascending=False)
df.to_csv(f"{topic.replace(' ', '_')}_geo_datasets.csv", index=False)
print(df[["accession", "title", "n_samples"]].head(10).to_string(index=False))

主要なパラメーター

パラメーターモジュールデフォルト範囲/オプション効果
destdirGEOparse.get_GEO"./"任意のディレクトリパスダウンロードしたファイルの保存先
silentGEOparse.get_GEOFalseTrue/Falseダウンロードの進行状況の出力を抑制します
retmaxESearch201–10000返されるデータセットレコードの最大数
entry type クエリESearch—"gse", "gds", "gpl", "gsm"GEO レコードの種類で絞り込みます
VALUE 列pivot_samples—GSM テーブル内の列名ピボットする発現値の列
emailE-utilities必須有効なメールアドレスNCBI のレート制限に関する連絡先情報

ベストプラクティス

  1. GEOparse では silent=True を使用する:冗長なダウンロード進行状況の出力を抑制できます。ダウンロードを確認するには、独自の print 文を追加してください。

  2. ダウンロードをキャッシュする:.soft.gz ファイルが destdir にすでに存在する場合、GEOparse は再ダウンロードをスキップします。重複したダウンロードを避けるには、セッション間で共通の destdir を設定してください。

  3. 大規模なデータセットでは Series Matrix を優先する:サンプル数が 100 件を超えるシリーズでは、個々の GSM soft ファイルを解析する代わりに、FTP から _series_matrix.txt.gz を直接ダウンロードしてください。処理速度が桁違いに向上します。

  4. プローブから遺伝子へのマッピングは慎重に扱う:多くのプローブは複数の遺伝子にマッピングされたり、どの遺伝子にもマッピングされなかったりします。解析前に、複数遺伝子に対応するプローブの扱い(除外、分割、または保持)を決めてください。Affymetrix アレイでは gene_symbol.str.split(" /// ") を使用します。

  5. プラットフォームの列名を確認する:GPL アノテーションテーブルの列名はプラットフォームによって異なります(例:"Gene Symbol"、"GENE_SYMBOL"、"gene_id")。フィールド名を決めつける前に、必ず gpl.table.columns を確認してください。

  6. 解析前に必ず SubSeries を解決する:GSE を読み込んだら、gse.metadata.get("relation", []) を調べて、"SuperSeries of: ..." のエントリーがあるか確認してください。ある場合は、参照されている各 SubSeries のアクセッションを順に確認し、それぞれをダウンロードしてください。SuperSeries レコード自体にはサンプルも発現行列も含まれていません。この手順を省略すると、実際のデータが気付かないうちに除外されます。

よく使うレシピ

レシピ:GSE メタデータを手早く確認する

使用場面:任意の GSE アクセッションについて、シリーズ名、サンプル数、プラットフォームを取得します。

import GEOparse

gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/", silent=True)
print(f"Title : {gse.metadata['title'][0]}")
print(f"Samples: {len(gse.gsms)}")
print(f"Platform: {list(gse.gpls.keys())}")
print(f"Summary: {gse.metadata['summary'][0][:300]}")
レシピ:サンプルの特性を抽出する

使用場面:GEO のサンプル特性を解析し、グループ分けに使える整然とした DataFrame にします。

import GEOparse, pandas as pd, re

gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/", silent=True)
meta = gse.phenotype_data

# Parse "characteristics_ch1" columns
ch_cols = [c for c in meta.columns if "characteristics" in c.lower()]
print(f"Characteristic columns: {ch_cols}")
print(meta[ch_cols].head())
レシピ:シリーズ内の全 GSM を一覧表示する

使用場面:ダウンロードやメタデータ収集のために、サンプルのアクセッションを列挙します。

import GEOparse

gse = GEOparse.get_GEO("GSE2553", destdir="./geo_data/", silent=True)
gsm_ids = list(gse.gsms.keys())
print(f"Total samples: {len(gsm_ids)}")
print("First 5:", gsm_ids[:5])

トラブルシューティング

問題原因解決策
ダウンロード中に FileNotFoundError が発生するdestdir が正しくない先にディレクトリを作成します:os.makedirs("geo_data/", exist_ok=True)
pivot_samples が空の DataFrame を返すGPL アノテーションテーブルに ID がないgpl.table.columns を確認し、正しいプローブ ID 列名を使用します
"Gene Symbol" の KeyError が発生するプラットフォームで別の列名が使われているgpl.table.columns を確認し、正しいアノテーション列を使用します
大規模なシリーズのダウンロードが停止するSOFT ファイルが大きい(GB 単位)大規模なシリーズでは GEOparse の代わりに FTP から Series Matrix をダウンロードします
ESearch の検索結果が 0 件になるentry type またはフィールドタグが誤っているgse[entry type] を gds[entry type] に切り替え、クエリの構文を確認します
数値のサンプル列に null が含まれる発現値が欠損または存在しないdf.fillna(0) で補完するか、欠損率の高い列を削除します
GSE にサンプルがない/gse.gsms が空アクセッションが SuperSeries であるgse.metadata["relation"] を解析して SuperSeries of: のエントリーを確認し、各 SubSeries をダウンロードします

関連スキル

  • cellxgene-census — scRNA-seq の GEO の代替として、大規模(6,100 万件以上の細胞)のシングルセル RNA-seq データを提供します
  • gene-database — GEO の研究で見つかった遺伝子に関する、精選されたアノテーション付きの NCBI Gene レコード
  • pubmed-database — NCBI ELink を使用して、GEO データセットに関連する論文を取得します
  • pydeseq2-differential-expression — GEO のカウントデータ読み込み後に行う下流の差次的発現解析

参考資料

コメント