tooluniverse-data-wrangling について
ToolUniverseを使う研究者向けに、さまざまなソースから科学データを取得・解析する方法をまとめたスキルです。形式別のPython例と、大量取得やツールの結果を超えるAPI利用パターンを掲載しています。
主な機能
- 01科学データ形式の解析例
- 02生物医学データベースのAPIパターン
- 03一括ダウンロードとページネーション
- 04ツールがない場合の直接API利用
活用シーン
- 01VCF、h5ad、BAMなどの解析
- 02データベースから大量のレコードを取得
- 03検索・絞り込み・取得・解析の連携
MCP 対応
ToolUniverseのツールとPython・直接APIの使い分けを案内するスキルです。MCPインターフェースについての説明はありません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mims-harvard/ tooluniverse --skill tooluniverse-data-wranglingインストール後、Claude Code で/tooluniverse-data-wranglingを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/specialized-domains.md
詳細
データラングリング:汎用アクセスパターン
あらゆるソースから科学データをダウンロードして解析するためのリファレンスです。各ステップで Bash を使って Python コードを記述し、実行します。
使用する場面
- ToolUniverse ツールからメタデータや検索結果は返されたものの、生データまたは一括データが必要な場合
- データがツールで解析できない形式(VCF、h5ad、BAM、SDF、GCT)である場合
- 複数ステップの API ワークフロー(検索 -> フィルタリング -> ダウンロード -> 解析)が必要な場合
- データソースに ToolUniverse ツールがまったくない場合
- ツールが返す 10~100 件ではなく、数千件のレコードが必要な場合
選択:ツールかコードか
| 状況 | 使用するもの |
|---|---|
| 1 件のレコードの検索、単純な検索、結果が 100 件未満 | ToolUniverse ツール(execute_tool) |
| 一括ダウンロード、カスタムフィルタリング、形式変換 | Python コードを記述 |
| ツールはあるが、結果が途中で切れている | ツールが使用するものと同じ API を使うコードを記述 |
| このソースに対応するツールがない | コードを直接記述 |
セクション A:形式別レシピ
表形式
import pandas as pd, io
df = pd.read_csv("data.csv") # CSV
df = pd.read_csv("data.tsv", sep="\t") # TSV
df = pd.read_sas(io.BytesIO(content), format="xport") # SAS Transport (XPT) — NHANES, CDC
df = pd.read_sas("data.sas7bdat", format="sas7bdat") # SAS native
df = pd.read_stata("data.dta") # Stata — ICPSR, HRS
df = pd.read_parquet("data.parquet") # Parquet — MIMIC-IV
df = pd.read_excel("data.xlsx") # Excel
df = pd.read_spss("data.sav") # SPSS
df = pd.read_fwf("data.dat") # Fixed-width — legacy surveys
ゲノミクス
from Bio import SeqIO
records = list(SeqIO.parse("seqs.fasta", "fasta")) # FASTA
records = list(SeqIO.parse("reads.fastq", "fastq")) # FASTQ
# VCF (no cyvcf2 needed)
vcf_lines = [l for l in open("vars.vcf") if not l.startswith("##")]
df = pd.read_csv(io.StringIO("".join(vcf_lines)), sep="\t")
df = pd.read_csv("genes.gff3", sep="\t", comment="#", # GFF/GTF
names=["seqid","source","type","start","end","score","strand","phase","attrs"])
df = pd.read_csv("regions.bed", sep="\t", header=None, # BED
names=["chrom","start","end","name","score","strand"])
import pysam # BAM (requires pysam)
bam = pysam.AlignmentFile("aligned.bam", "rb")
for read in bam.fetch("chr1", 1000, 2000): print(read.query_name)
構造
from Bio.PDB import PDBParser, MMCIFParser
parser = PDBParser(QUIET=True)
structure = parser.get_structure("prot", "structure.pdb") # PDB
parser = MMCIFParser(QUIET=True)
structure = parser.get_structure("prot", "structure.cif") # mmCIF
from rdkit import Chem # SDF/MOL (requires rdkit)
supplier = Chem.SDMolSupplier("compounds.sdf")
mols = [m for m in supplier if m is not None]
オミクス行列
import anndata
adata = anndata.read_h5ad("expression.h5ad") # AnnData (scRNA-seq, spatial)
import scipy.io
mat = scipy.io.mmread("matrix.mtx") # 10X Genomics MTX
barcodes = pd.read_csv("barcodes.tsv", header=None)[0].tolist()
features = pd.read_csv("features.tsv", sep="\t", header=None)[1].tolist()
df = pd.read_csv("expression.gct", sep="\t", skiprows=2) # GCT (gene expression)
import loompy # Loom (legacy single-cell)
ds = loompy.connect("data.loom")
質量分析・フローサイトメトリー
from pyteomics import mzml # mzML (proteomics, requires pyteomics)
spectra = list(mzml.read("spectra.mzML"))
import fcsparser # FCS (flow cytometry, requires fcsparser)
meta, data = fcsparser.parse("sample.fcs", reformat_meta=True)
ニューロイメージング
import nibabel as nib # NIfTI (requires nibabel)
img = nib.load("brain.nii.gz")
data = img.get_fdata() # 3D/4D numpy array
# DICOM (requires pydicom)
import pydicom
dcm = pydicom.dcmread("scan.dcm")
pixel_data = dcm.pixel_array
系統発生学・システム生物学
from Bio import Phylo # Newick/Nexus (BioPython)
tree = Phylo.read("tree.nwk", "newick")
tree = Phylo.read("tree.nex", "nexus")
import libsbml # SBML (systems biology, requires python-libsbml)
reader = libsbml.SBMLReader()
doc = reader.readSBML("model.xml")
model = doc.getModel()
シリアライズ形式
import json, xml.etree.ElementTree as ET, h5py
data = json.load(open("data.json")) # JSON
df = pd.read_json("records.json") # JSON -> DataFrame
tree = ET.parse("data.xml"); root = tree.getroot() # XML
f = h5py.File("data.h5", "r"); dataset = f["group/data"][:] # HDF5
圧縮形式
df = pd.read_csv("data.csv.gz") # gzip (pandas auto-detects)
df = pd.read_csv("data.tsv.gz", sep="\t") # gzip TSV
import zipfile
with zipfile.ZipFile(io.BytesIO(content)) as z: # ZIP
df = pd.read_csv(z.open(z.namelist()[0]))
import tarfile
with tarfile.open("archive.tar.gz") as t: # tar.gz
f = t.extractfile(t.getnames()[0])
df = pd.read_csv(f)
セクション B:分野別 API パターン
各カテゴリでは、利用可能な ToolUniverse ツールと、直接 API 呼び出しでその機能を超える方法を紹介します。
1. NCBI E-utilities(遺伝子、ヌクレオチド、タンパク質、SRA、GEO)
ツール:NCBIGene_search、NCBI_search_nucleotide、SRA_search_experiments、geo_search_datasets
import requests
base = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
# Search -> get IDs -> fetch records in batches
ids = requests.get(f"{base}/esearch.fcgi?db=gene&term=BRCA1+AND+human&retmax=500&retmode=json").json()
id_list = ids["esearchresult"]["idlist"]
# Fetch in batches of 500
for i in range(0, len(id_list), 500):
batch = ",".join(id_list[i:i+500])
data = requests.get(f"{base}/efetch.fcgi?db=gene&id={batch}&retmode=xml").text
2. EBI API(UniProt、PDBe、ChEMBL、Ensembl、InterPro)
ツール:UniProt_search、PDBe_*、ChEMBL_*、Ensembl_*、InterPro_*
# UniProt bulk TSV download with cursor pagination
url = "https://rest.uniprot.org/uniprotkb/search?query=organism_id:9606+AND+keyword:kinase&format=tsv&size=500"
all_rows = []
while url:
resp = requests.get(url)
all_rows.append(resp.text)
url = resp.headers.get("Link", "").split(";")[0].strip("<>") if "Link" in resp.headers else None
3. NCI GDC(TCGA/TARGET のがんデータ)
ツール:GDC_search_cases、GDC_list_files、GDC_get_clinical_data
# Bulk clinical data with filters
filters = {"op":"and","content":[
{"op":"=","content":{"field":"project.project_id","value":"TCGA-BRCA"}},
{"op":"=","content":{"field":"demographic.vital_status","value":"Dead"}}
]}
cases = requests.post("https://api.gdc.cancer.gov/cases", json={
"filters": filters, "fields": "demographic.vital_status,diagnoses.days_to_death",
"size": 1000, "from": 0
}).json()["data"]["hits"]
4. CDC の健康調査(NHANES、BRFSS、WONDER)
ツール:NHANES_download_and_parse、cdc_data_search_datasets
# Direct NHANES XPT download (any cycle, any component)
cycle, component = "2017-2018", "DEMO_J"
url = f"https://wwwn.cdc.gov/Nchs/Data/Nhanes/Public/2017/DataFiles/{component}.XPT"
df = pd.read_sas(io.BytesIO(requests.get(url).content), format="xport")
5. GWAS・遺伝学(GWAS Catalog、gnomAD、ClinVar)
ツール:gwas_search_associations、gnomAD_*、ClinVar_*
# GWAS Catalog full download (37MB TSV, all associations)
url = "https://www.ebi.ac.uk/gwas/api/search/downloads/alternative"
df = pd.read_csv(url, sep="\t")
# Filter locally
hits = df[df["DISEASE/TRAIT"].str.contains("diabetes", case=False, na=False)]
6. 化学物質(PubChem、ChEMBL、KEGG)
ツール:PubChem_*、ChEMBL_*、KEGG_*
# PubChem batch property retrieval (up to 100 CIDs at once)
cids = "2244,5988,3672" # aspirin, sucrose, ibuprofen
url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cids}/property/MolecularWeight,XLogP,TPSA/JSON"
props = requests.get(url).json()["PropertyTable"]["Properties"]
7. 発現(GEO、ArrayExpress、GTEx)
ツール:geo_search_datasets、arrayexpress_search_experiments
# GEO series matrix direct download
geo_id = "GSE12345"
url = f"https://ftp.ncbi.nlm.nih.gov/geo/series/{geo_id[:5]}nnn/{geo_id}/matrix/{geo_id}_series_matrix.txt.gz"
df = pd.read_csv(url, sep="\t", comment="!", index_col=0)
# GTEx bulk expression (median TPM per tissue)
url = "https://storage.googleapis.com/adult-gtex/bulk-gex/v8/rna-seq/GTEx_Analysis_2017-06-05_v8_RNASeQCv1.1.9_gene_median_tpm.gct.gz"
df = pd.read_csv(url, sep="\t", skiprows=2)
8. 臨床(ClinicalTrials.gov、FDA/OpenFDA、FAERS)
ツール:search_clinical_trials、OpenFDA_*
# ClinicalTrials.gov v2 API with pagination
all_studies = []
token = None
while True:
params = {"query.cond": "lung cancer", "query.intr": "immunotherapy", "pageSize": 100}
if token: params["pageToken"] = token
resp = requests.get("https://clinicaltrials.gov/api/v2/studies", params=params).json()
all_studies.extend(resp.get("studies", []))
token = resp.get("nextPageToken")
if not token: break
9. 文献(PubMed、PMC、EuropePMC)
ツール:PubMed_search_articles、EuropePMC_search_articles
# EuropePMC full-text search with cursor
cursor = "*"
all_results = []
while cursor:
resp = requests.get("https://www.ebi.ac.uk/europepmc/webservices/rest/search",
params={"query": "BRCA1 AND resistance", "format": "json", "pageSize": 100, "cursorMark": cursor}).json()
all_results.extend(resp.get("resultList", {}).get("result", []))
cursor = resp.get("nextCursorMark") if len(all_results) < resp.get("hitCount", 0) else None
10. データリポジトリ(Zenodo、Figshare、Dryad、DataCite)
ツール:DataCite_search_dois、Zenodo_search_records、Dryad_search_datasets
# Zenodo: search + download files
record = requests.get("https://zenodo.org/api/records", params={"q": "proteomics cancer", "size": 5}).json()["hits"]["hits"][0]
for f in record["files"]:
content = requests.get(f["links"]["self"]).content # download each file
11~24. 専門分野
以下の 14 の追加分野について、特定の API パターンが必要な場合は references/specialized-domains.md を参照してください。
| # | 分野 | 主な API/ツール | 参照する場面 |
|---|---|---|---|
| 11 | プロテオミクス | PRIDE、MassIVE、ProteomeXchange | 質量分析データのダウンロード |
| 12 | メタボロミクス | MetaboLights、Metabolomics Workbench、HMDB | 代謝物/スペクトルデータ |
| 13 | マイクロバイオーム | MGnify、GMREPO | メタゲノムプロファイル |
| 14 | 生態学 | GBIF、iNaturalist、OBIS | 種の出現データ |
| 15 | モデル生物 | FlyBase、WormBase、ZFIN、RGD | ヒト以外の種の遺伝子データ |
| 16 | パスウェイ・ネットワーク | Reactome、STRING、BioGRID | ネットワーク/パスウェイのエクスポート |
| 17 | オントロジー | OLS、GO、HPO | 用語階層のたどり方 |
| 18 | 免疫学 | IEDB、VDJdb、ImmPort | エピトープ/受容体データ |
| 19 | 医薬品・製薬 | PharmGKB、DGIdb、SIDER | 医薬品と遺伝子の相互作用 |
| 20 | イメージング・アトラス | TCIA、HPA、Allen Brain Atlas | 画像コレクション |
| 21 | タンパク質構造 | RCSB PDB、AlphaFold | PDB/CIF ファイルのダウンロード |
| 22 | 臨床ゲノミクス | ClinVar、ClinGen、CIViC | バリアント解釈の一括処理 |
| 23 | シングルセル | cellxgene、ARCHS4 | scRNA-seq データポータル |
| 24 | 毒性学 | CTD、EPA CompTox | 化学物質・遺伝子・疾患 |
セクション C:制限付き/未対応のデータソース
これらのデータソースは登録が必要であるか、対応する ToolUniverse ツールがありません。各データソースについて、表にアクセス要件と、認証情報を取得した後にプログラムでデータを取得する方法を示します。
注:ToolUniverse には 2300 以上のツールがあります。上記に記載されていないツールを見つけるには、find_tools("your topic") を使用してください。セクション B では、最も一般的な API の パターン を取り上げています。ほかにも多くのデータベースが同じパターンを使用しています(例:EBI のすべてのデータベースは、#2 の EBI REST パターンに従います)。
| データソース | アクセス | 待ち時間 | 形式 | 内容 |
|---|---|---|---|---|
| UK Biobank | 制限付き(機関経由) | 2~6 か月 | CSV/Bulk | 50 万人の参加者、遺伝情報+画像+健康記録 |
| dbGaP | 管理付き(研究代表者による申請) | 1~3 か月 | SRA/VCF/phenotype | 数千件の研究から得られた GWAS の遺伝型+表現型 |
| MIMIC-IV | 認証が必要(PhysioNet) | 1~2 週間 | CSV/Parquet | ICU の臨床データ、30 万件以上の入院記録 |
| ICPSR | 登録 | 1~3 日 | Stata/CSV | 社会科学/健康科学のアーカイブ(1 万件以上の研究) |
| HRS | 登録 | 1~3 日 | Stata | Health & Retirement Study、2 万人以上の高齢アメリカ人を対象とした隔年調査 |
| ELSA | 登録 | 1~3 日 | Stata/SPSS | 英国の高齢化に関する縦断研究 |
| SHARE | 登録 | 1~2 週間 | Stata | 欧州の健康・高齢化・退職に関する調査(28 か国) |
| Materials Project | 無料の API キー | 即時 | JSON | 15 万件以上の計算材料物性 |
| Human Cell Atlas | オープン | 即時 | h5ad/loom | ヒト組織全体を対象とする単一細胞アトラス |
| ADNI | 申請 | 1~2 か月 | DICOM/CSV | アルツハイマー病の神経画像+バイオマーカー+認知機能 |
| OpenNeuro | オープン | 即時 | NIfTI/BIDS | 800 件以上の神経画像データセット |
| CIBERSORTx | 無料登録 | 即時 | GCT/TSV | バルク発現データからの細胞型デコンボリューション |
| FlowRepository | オープン | 即時 | FCS | フローサイトメトリー実験 |
| SynBioHub | オープン | 即時 | SBOL/GenBank | 合成生物学のパーツと設計 |
制限付きのデータソースについては、そのデータセットを使用した公開済みの解析を文献(PubMed)で検索してください。論文にはデータソースが記載されており、多くの場合、派生データが公開リポジトリ(GEO、SRA、Zenodo)に登録されています。
セクション D:汎用パターン
ページネーション
# Pattern 1: offset + limit (most REST APIs)
all_records = []
offset = 0
while True:
resp = requests.get(f"{api_url}?offset={offset}&limit=500", timeout=30).json()
batch = resp.get("data", resp.get("results", resp.get("hits", [])))
if not batch: break
all_records.extend(batch)
offset += len(batch)
# Pattern 2: cursor/token (EuropePMC, ClinicalTrials.gov, UniProt)
token = None
while True:
params = {"pageSize": 100}
if token: params["pageToken"] = token
resp = requests.get(api_url, params=params).json()
all_records.extend(resp["results"])
token = resp.get("nextPageToken")
if not token: break
レート制限と再試行
import time
def fetch_with_retry(url, max_retries=3, **kwargs):
for attempt in range(max_retries):
resp = requests.get(url, timeout=30, **kwargs)
if resp.status_code == 200: return resp
if resp.status_code == 429: # rate limited
wait = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
else:
time.sleep(2 ** attempt)
raise RuntimeError(f"Failed after {max_retries} retries: {url}")
認証
import os
# API key in header (most common)
headers = {"Authorization": f"Bearer {os.environ.get('API_KEY', '')}"}
# API key as query param
params = {"api_key": os.environ.get("API_KEY", "")}
# No auth needed for most scientific APIs (NCBI, EBI, PubChem, GDC, CDC)
ストリーミングによる一括ダウンロード
def download_large_file(url, output_path):
with requests.get(url, stream=True, timeout=300) as r:
r.raise_for_status()
with open(output_path, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
エラー処理
resp = requests.get(url, timeout=30)
if resp.status_code != 200:
raise ValueError(f"HTTP {resp.status_code}: {resp.text[:200]}")
# Guard against HTML error pages (CDC, NCBI return 200 with HTML for missing files)
if resp.content[:5] in (b"<!DOC", b"<html"):
raise ValueError(f"Server returned HTML error page for {url}")
data = resp.json() # raises JSONDecodeError if not valid JSON