anndata

Par mkurman · zorai

Structure de données pour les matrices annotées en analyse de cellules uniques. À utiliser pour travailler avec des fichiers `.h5ad` ou pour s'intégrer à l'écosystème scverse. Il s'agit du skill de format de données — pour les workflows d'analyse, utilisez scanpy ; pour les modèles probabilistes, utilisez scvi-tools ; pour les requêtes à l'échelle de la population, utilisez cellxgene-census.

npx skills add https://github.com/mkurman/zorai --skill anndata

AnnData

Aperçu

AnnData est un package Python pour manipuler des matrices de données annotées, stockant les mesures expérimentales (X) aux côtés des métadonnées d'observation (obs), des métadonnées de variable (var) et des annotations multi-dimensionnelles (obsm, varm, obsp, varp, uns). Conçu à l'origine pour la génomique unicellulaire via Scanpy, il sert désormais de framework polyvalent pour toute donnée annotée nécessitant un stockage, une manipulation et une analyse efficaces.

Quand utiliser cette compétence

Utilisez cette compétence quand :

  • Créer, lire ou écrire des objets AnnData
  • Travailler avec les formats h5ad, zarr ou autres formats de données génomiques
  • Effectuer une analyse d'ARNseq unicellulaire
  • Gérer de grands ensembles de données avec matrices creuses ou mode backed
  • Concaténer plusieurs ensembles de données ou lots expérimentaux
  • Sous-ensembler, filtrer ou transformer des données annotées
  • Intégrer avec scanpy, scvi-tools ou d'autres outils de l'écosystème scverse

Installation

uv pip install anndata

# Avec dépendances optionnelles
uv pip install anndata[dev,test,doc]

Démarrage rapide

Créer un objet AnnData

import anndata as ad
import numpy as np
import pandas as pd

# Création minimale
X = np.random.rand(100, 2000)  # 100 cellules × 2000 gènes
adata = ad.AnnData(X)

# Avec métadonnées
obs = pd.DataFrame({
    'cell_type': ['T cell', 'B cell'] * 50,
    'sample': ['A', 'B'] * 50
}, index=[f'cell_{i}' for i in range(100)])

var = pd.DataFrame({
    'gene_name': [f'Gene_{i}' for i in range(2000)]
}, index=[f'ENSG{i:05d}' for i in range(2000)])

adata = ad.AnnData(X=X, obs=obs, var=var)

Lire des données

# Lire un fichier h5ad
adata = ad.read_h5ad('data.h5ad')

# Lire avec mode backed (pour gros fichiers)
adata = ad.read_h5ad('large_data.h5ad', backed='r')

# Lire d'autres formats
adata = ad.read_csv('data.csv')
adata = ad.read_loom('data.loom')
adata = ad.read_10x_h5('filtered_feature_bc_matrix.h5')

Écrire des données

# Écrire un fichier h5ad
adata.write_h5ad('output.h5ad')

# Écrire avec compression
adata.write_h5ad('output.h5ad', compression='gzip')

# Écrire d'autres formats
adata.write_zarr('output.zarr')
adata.write_csvs('output_dir/')

Opérations basiques

# Sous-ensembler par conditions
t_cells = adata[adata.obs['cell_type'] == 'T cell']

# Sous-ensembler par indices
subset = adata[0:50, 0:100]

# Ajouter des métadonnées
adata.obs['quality_score'] = np.random.rand(adata.n_obs)
adata.var['highly_variable'] = np.random.rand(adata.n_vars) > 0.8

# Accéder aux dimensions
print(f"{adata.n_obs} observations × {adata.n_vars} variables")

Capacités principales

1. Structure de données

Comprendre la structure de l'objet AnnData incluant X, obs, var, layers, obsm, varm, obsp, varp, uns et les composants raw.

Voir : references/data_structure.md pour des informations complètes sur :

  • Composants principaux (X, obs, var, layers, obsm, varm, obsp, varp, uns, raw)
  • Créer des objets AnnData à partir de diverses sources
  • Accéder et manipuler les composants de données
  • Pratiques efficaces en mémoire

2. Opérations d'entrée/sortie

Lire et écrire des données dans différents formats avec support de la compression, du mode backed et du stockage cloud.

Voir : references/io_operations.md pour des détails sur :

  • Formats natifs (h5ad, zarr)
  • Formats alternatifs (CSV, MTX, Loom, 10X, Excel)
  • Mode backed pour gros ensembles de données
  • Accès à données distantes
  • Conversion de formats
  • Optimisation des performances

Commandes courantes :

# Lire/écrire h5ad
adata = ad.read_h5ad('data.h5ad', backed='r')
adata.write_h5ad('output.h5ad', compression='gzip')

# Lire données 10X
adata = ad.read_10x_h5('filtered_feature_bc_matrix.h5')

# Lire format MTX
adata = ad.read_mtx('matrix.mtx').T

3. Concaténation

Combiner plusieurs objets AnnData selon les observations ou les variables avec stratégies de jointure flexibles.

Voir : references/concatenation.md pour une couverture complète de :

  • Concaténation basique (axis=0 pour observations, axis=1 pour variables)
  • Types de jointure (inner, outer)
  • Stratégies de fusion (same, unique, first, only)
  • Tracer les sources de données avec labels
  • Concaténation lazy (AnnCollection)
  • Concaténation sur disque pour gros ensembles de données

Commandes courantes :

# Concaténer observations (combiner samples)
adata = ad.concat(
    [adata1, adata2, adata3],
    axis=0,
    join='inner',
    label='batch',
    keys=['batch1', 'batch2', 'batch3']
)

# Concaténer variables (combiner modalités)
adata = ad.concat([adata_rna, adata_protein], axis=1)

# Concaténation lazy
from anndata.experimental import AnnCollection
collection = AnnCollection(
    ['data1.h5ad', 'data2.h5ad'],
    join_obs='outer',
    label='dataset'
)

4. Manipulation de données

Transformer, sous-ensembler, filtrer et réorganiser les données efficacement.

Voir : references/manipulation.md pour des conseils détaillés sur :

  • Sous-ensembler (par indices, noms, masques booléens, conditions de métadonnées)
  • Transposition
  • Copie (copies complètes vs vues)
  • Renommage (observations, variables, catégories)
  • Conversions de type (chaînes en catégories, creux/dense)
  • Ajouter/supprimer des composants de données
  • Réordonner
  • Filtrage du contrôle qualité

Commandes courantes :

# Sous-ensembler par métadonnées
filtered = adata[adata.obs['quality_score'] > 0.8]
hv_genes = adata[:, adata.var['highly_variable']]

# Transposer
adata_T = adata.T

# Copie vs vue
view = adata[0:100, :]  # Vue (référence légère)
copy = adata[0:100, :].copy()  # Copie indépendante

# Convertir chaînes en catégories
adata.strings_to_categoricals()

5. Bonnes pratiques

Suivre les modèles recommandés pour l'efficacité mémoire, les performances et la reproductibilité.

Voir : references/best_practices.md pour des conseils sur :

  • Gestion de la mémoire (matrices creuses, catégories, mode backed)
  • Vues vs copies
  • Optimisation du stockage de données
  • Optimisation des performances
  • Travailler avec données raw
  • Gestion des métadonnées
  • Reproductibilité
  • Gestion des erreurs
  • Intégration avec d'autres outils
  • Pièges courants et solutions

Recommandations clés :

# Utiliser matrices creuses pour données creuses
from scipy.sparse import csr_matrix
adata.X = csr_matrix(adata.X)

# Convertir chaînes en catégories
adata.strings_to_categoricals()

# Utiliser mode backed pour gros fichiers
adata = ad.read_h5ad('large.h5ad', backed='r')

# Stocker raw avant filtrage
adata.raw = adata.copy()
adata = adata[:, adata.var['highly_variable']]

Intégration avec l'écosystème Scverse

AnnData sert de structure de données fondatrice pour l'écosystème scverse :

Scanpy (Analyse unicellulaire)

import scanpy as sc

# Prétraitement
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata, n_top_genes=2000)

# Réduction de dimensionnalité
sc.pp.pca(adata, n_comps=50)
sc.pp.neighbors(adata, n_neighbors=15)
sc.tl.umap(adata)
sc.tl.leiden(adata)

# Visualisation
sc.pl.umap(adata, color=['cell_type', 'leiden'])

Muon (Données multimodales)

import muon as mu

# Combiner données ARN et protéine
mdata = mu.MuData({'rna': adata_rna, 'protein': adata_protein})

Intégration PyTorch

from anndata.experimental import AnnLoader

# Créer DataLoader pour deep learning
dataloader = AnnLoader(adata, batch_size=128, shuffle=True)

for batch in dataloader:
    X = batch.X
    # Entraîner modèle

Workflows courants

Analyse d'ARNseq unicellulaire

import anndata as ad
import scanpy as sc

# 1. Charger données
adata = ad.read_10x_h5('filtered_feature_bc_matrix.h5')

# 2. Contrôle qualité
adata.obs['n_genes'] = (adata.X > 0).sum(axis=1)
adata.obs['n_counts'] = adata.X.sum(axis=1)
adata = adata[adata.obs['n_genes'] > 200]
adata = adata[adata.obs['n_counts'] < 50000]

# 3. Stocker raw
adata.raw = adata.copy()

# 4. Normaliser et filtrer
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata, n_top_genes=2000)
adata = adata[:, adata.var['highly_variable']]

# 5. Sauvegarder données traitées
adata.write_h5ad('processed.h5ad')

Intégration de lots

# Charger plusieurs lots
adata1 = ad.read_h5ad('batch1.h5ad')
adata2 = ad.read_h5ad('batch2.h5ad')
adata3 = ad.read_h5ad('batch3.h5ad')

# Concaténer avec labels de lot
adata = ad.concat(
    [adata1, adata2, adata3],
    label='batch',
    keys=['batch1', 'batch2', 'batch3'],
    join='inner'
)

# Appliquer correction de lot
import scanpy as sc
sc.pp.combat(adata, key='batch')

# Continuer l'analyse
sc.pp.pca(adata)
sc.pp.neighbors(adata)
sc.tl.umap(adata)

Travailler avec de gros ensembles de données

# Ouvrir en mode backed
adata = ad.read_h5ad('100GB_dataset.h5ad', backed='r')

# Filtrer basé sur métadonnées (sans charger données)
high_quality = adata[adata.obs['quality_score'] > 0.8]

# Charger sous-ensemble filtré
adata_subset = high_quality.to_memory()

# Traiter sous-ensemble
process(adata_subset)

# Ou traiter par chunks
chunk_size = 1000
for i in range(0, adata.n_obs, chunk_size):
    chunk = adata[i:i+chunk_size, :].to_memory()
    process(chunk)

Dépannage

Erreurs de mémoire insuffisante

Utilisez le mode backed ou convertissez en matrices creuses :

# Mode backed
adata = ad.read_h5ad('file.h5ad', backed='r')

# Matrices creuses
from scipy.sparse import csr_matrix
adata.X = csr_matrix(adata.X)

Lecture de fichiers lente

Utilisez la compression et les formats appropriés :

# Optimiser pour stockage
adata.strings_to_categoricals()
adata.write_h5ad('file.h5ad', compression='gzip')

# Utiliser Zarr pour stockage cloud
adata.write_zarr('file.zarr', chunks=(1000, 1000))

Problèmes d'alignement d'index

Toujours aligner données externes sur l'index :

# Incorrect
adata.obs['new_col'] = external_data['values']

# Correct
adata.obs['new_col'] = external_data.set_index('cell_id').loc[adata.obs_names, 'values']

Ressources supplémentaires

Skills similaires