geo-database について
geo-databaseは、NCBI GEOの公開機能ゲノミクス記録を検索、ダウンロード、解析するスキルです。GEOparseとNCBI E-utilitiesを使い、GEOシリーズ、発現データ、サンプルメタデータを取得できます。
主な機能
- 01E-utilitiesによるGEO記録の検索
- 02GSE・GPL・GSM記録のダウンロードと解析
- 03発現行列とサンプルメタデータの抽出
- 04プラットフォームのプローブと遺伝子注釈の対応付け
- 05FTPから大型シリーズ行列ファイルを取得
活用シーン
- 01生物種・組織・条件で研究を検索
- 02差次的発現解析用のGEO発現データを準備
- 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))
主要なパラメーター
| パラメーター | モジュール | デフォルト | 範囲/オプション | 効果 |
|---|---|---|---|---|
destdir | GEOparse.get_GEO | "./" | 任意のディレクトリパス | ダウンロードしたファイルの保存先 |
silent | GEOparse.get_GEO | False | True/False | ダウンロードの進行状況の出力を抑制します |
retmax | ESearch | 20 | 1–10000 | 返されるデータセットレコードの最大数 |
entry type クエリ | ESearch | — | "gse", "gds", "gpl", "gsm" | GEO レコードの種類で絞り込みます |
VALUE 列 | pivot_samples | — | GSM テーブル内の列名 | ピボットする発現値の列 |
email | E-utilities | 必須 | 有効なメールアドレス | NCBI のレート制限に関する連絡先情報 |
ベストプラクティス
-
GEOparse では
silent=Trueを使用する:冗長なダウンロード進行状況の出力を抑制できます。ダウンロードを確認するには、独自の print 文を追加してください。 -
ダウンロードをキャッシュする:
.soft.gzファイルがdestdirにすでに存在する場合、GEOparse は再ダウンロードをスキップします。重複したダウンロードを避けるには、セッション間で共通のdestdirを設定してください。 -
大規模なデータセットでは Series Matrix を優先する:サンプル数が 100 件を超えるシリーズでは、個々の GSM soft ファイルを解析する代わりに、FTP から
_series_matrix.txt.gzを直接ダウンロードしてください。処理速度が桁違いに向上します。 -
プローブから遺伝子へのマッピングは慎重に扱う:多くのプローブは複数の遺伝子にマッピングされたり、どの遺伝子にもマッピングされなかったりします。解析前に、複数遺伝子に対応するプローブの扱い(除外、分割、または保持)を決めてください。Affymetrix アレイでは
gene_symbol.str.split(" /// ")を使用します。 -
プラットフォームの列名を確認する:GPL アノテーションテーブルの列名はプラットフォームによって異なります(例:
"Gene Symbol"、"GENE_SYMBOL"、"gene_id")。フィールド名を決めつける前に、必ずgpl.table.columnsを確認してください。 -
解析前に必ず 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 のカウントデータ読み込み後に行う下流の差次的発現解析
参考資料
- GEO database home — GEO データセットの閲覧と検索
- GEOparse GitHub — Python ライブラリのドキュメントと使用例
- GEO FTP server — シリーズ、サンプル、プラットフォームのファイルに直接アクセス
- NCBI E-utilities for GEO —
gdsデータベースの ESearch/ESummary API リファレンス