An AI system to help scientists write expert-level empirical software.
The 11 matches
- [1] § Methods › scRNA-seq batch integration › Dataset ↔ implementation/notebooks/single_cell_batch_integration.ipynb, lines 407–426 · score 0.83 · c1 ae26872b1042, bd0c7 f7fd, ed, cells, batches
- [2] § Methods › Code mutation system ↔ implementation/futs.py, lines 15–23 · score 0.71 · upper confidence bound, AlphaZero, tree search, UCB, Flat, algorithm
- [3] § Methods › COVID-19 prediction › Dataset ↔ implementation/notebooks/flu-cornell-jhu-hierarchsir.ipynb, lines 1–148 · score 0.71 · hospital admissions, Forecast Hub, target variable, augment, jurisdiction, population
- [4] § Methods › scRNA-seq batch integration › Evaluating scRNA-seq batch integration on the OpenProblems.bio benchmark ↔ implementation/notebooks/single_cell_batch_integration.ipynb, lines 864–965 · score 0.64 · cellxgene_census, batch integration, uns, OpenProblems, bounds, score
- [5] § Public health: predicting COVID-19 hospitalizations ↔ implementation/notebooks/flu-cornell-jhu-hierarchsir.ipynb, lines 1–148 · score 0.62 · weighted interval score, Forecast Hub, week, territories, uncertainty, calibrated
- [6] § Methods › GIFT-Eval benchmark › Unified solution ↔ implementation/notebooks/single_cell_batch_integration.ipynb, lines 753–786 · score 0.60 · log1p, log transform, median
- [7] § Methods › Code mutation system ↔ implementation/futs.py, lines 96–155 · score 0.60 · search tree, backpropagation, visit, flat, PUCT, exploration
- [8] § Genomics: batch integration of scRNA-seq data ↔ implementation/notebooks/single_cell_batch_integration.ipynb, lines 864–965 · score 0.59 · single cell batch, batch integration, mouse, OpenProblems, prompt, metrics
- [9] § Methods › scRNA-seq batch integration › Replication of existing methods for batch integration ↔ scripts/validate_results.py, lines 31–71 · score 0.56 · fine tuned, zero shot, leakage, metrics, model
- [10] § Time-series forecasting: GIFT-Eval › Per-dataset solution ↔ implementation/playground_s3e1.py, lines 66–125 · score 0.53 · scikit learn, XGBoost, boosting, Python, models
- [11] § Methods › Code mutation system ↔ implementation/futs.py, lines 96–155 · score 0.53 · rank scores, tree search, UCB, flat, PUCT, exploration
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 968 lines · 33 KB · Apache-2.0 · 4 matches
- # %% [markdown]
- # # Overview
- #
- # As single-cell technologies advance, single-cell datasets are growing both in
- # size and complexity. Especially in consortia such as the Human Cell Atlas,
- # individual studies combine data from multiple labs, each sequencing multiple
- # individuals possibly with different technologies. This gives rise to complex
- # batch effects in the data that must be computationally removed to perform a
- # joint analysis.
- #
- # This task aims to develop a superhuman method for batch integration of
- # single-cell RNA-seq data which must remove the batch effect while not removing
- # relevant biological information. The input data is unnormalized raw gene
- # expression count data with multiple batches and consistent cell type labels. The
- # batch integrated output can be a low dimensional embedding of the data or a
- # feature matrix. The respective batch-integrated representation is then evaluated
- # using sets of metrics that capture how well batch effects are removed and
- # whether biological variance is conserved. There are over 200 methods developed
- # by humans for carrying this out and the goal is to develop methods that are
- # better than humans.
- # %% [markdown]
- # **Input Format:** The input data file (`input_adata`) is an `ad.AnnData` object
- # that includes the main data matrix in `.X` attribute (these are input raw gene
- # expression counts we want to transform). The data has already been subset to
- # 2000 highly variable genes.
- #
- # **Output Format:** The output data (`output_adata`) MUST be an `ad.AnnData`
- # object. The transformed dataset or embedding must be stored in `X_emb` key under
- # `obsm` annotation.
- #
- # ```
- # output_data = ad.AnnData(
- # obs=adata.obs,
- # var=adata.var,
- # obsm={
- # 'X_emb': # transformed dataset goes here.
- # },
- # )
- # ```
- #
- # Importantly, **to remove batch effects while conserving biological factors you
- # may experiment with data preprocessing (e.g. via scanpy) as well as modeling.**
- #
- # **Evaluation Harness and `eliminate_batch_effect_fn`:** You will implement a
- # function, `eliminate_batch_effect_fn`, to generate a transformed dataset that
- # represents the original data without batch effects. The evaluation harness will
- # evaluate via `score` function below whether the transformed datasets has
- # eliminated batch effects while preserving important biological features. In
- # particular, we would like to preserve cell type variation. The `score` function
- # implements various metrics used to measure how well you are doing on the task.
- # Your goal is to maximize the score from the `score` function below by writing
- # the best possible method/code for `eliminate_batch_effect_fn`.
- #
- # **1. Objective:**
- #
- # * The goal is to create a `eliminate_batch_effect_fn` that transforms the
- # dataset into a new dataset that not only eliminiates batch effects but
- # preserves biological information. We will evaluate the output using average
- # of the following specific metrics (after scaling):
- # * ASW Batch: Modified average silhouette width (ASW) of batch. The metric
- # is scaled so that 0 indicates suboptimal batch mixing and 1 indicates
- # optimal batch mixing.
- # * ASW Label: Average silhouette width of cell type labels. ASW is computed
- # on cell identity labels and scaled to a value between 0 (worst) and 1
- # (best).
- # * ARI: Adjusted Rand Index compares clustering overlap, correcting for
- # random labels and considering correct overlaps and disagreements. The
- # Adjusted Rand Index (ARI) compares the overlap of two clusterings; it
- # considers both correct clustering overlaps while also counting correct
- # disagreements between two clusterings. We compare the cell-type labels
- # with the NMI-optimized Louvain clustering computed on the integrated
- # dataset. The adjustment of the Rand index corrects for randomly correct
- # labels. An ARI of 0 or 1 corresponds to random labeling or a perfect
- # match, respectively. The score ranges between 0 and 1 with larger values
- # indicating better conservation of the data-driven cell identity
- # discovery after integration compared to annotated labels.
- # * NMI: The normalized mutual information is a version of the mutual
- # information corrected by the entropy of clustering and ground truth
- # labels (e.g. cell type). The score ranges between 0 and 1, with 0
- # representing no sharing and 1 representing perfect sharing of
- # information between clustering and annotated cell labels. NMI compares
- # overlap by scaling using mean entropy terms and optimizing Louvain
- # clustering to obtain the best match between clusters and labels.
- # Normalized Mutual Information (NMI) compares the overlap of two
- # clusterings. We use NMI to compare the cell-type labels with Louvain
- # clusters computed on the integrated dataset. The overlap was scaled
- # using the mean of the entropy terms for cell-type and cluster labels.
- # Thus, NMI scores of 0 or 1 correspond to uncorrelated clustering or a
- # perfect match, respectively. We performe optimized Louvain clustering
- # for this metric to obtain the best match between clusters and labels.
- # * Graph connectivity: Connectivity of the subgraph per cell type label.
- # The graph connectivity metric assesses whether the kNN graph
- # representation, G, of the integrated data directly connects all cells
- # with the same cell identity label. The resultant score has a range of
- # (0;1], where 1 indicates that all cells with the same cell identity are
- # connected in the integrated kNN graph, and the lowest possible score
- # indicates a graph where no cell is connected.
- # * Isolated labels ASW: Score how well isolated labels are distinguished
- # from all other labels using the average-width silhouette score. Isolated
- # cell labels are defined as the labels present in the least number of
- # batches in the integration task. The score evaluates how well these
- # isolated labels separate from other cell identities. The isolated label
- # ASW score is obtained by computing the ASW of isolated versus
- # non-isolated labels on the embedding and scaling this score to be
- # between 0 and 1. The final score for each metric version consists of the
- # mean isolated score of all isolated labels.
- # * Isolated labels F1: Evaluate how well isolated labels coincide with
- # clusters. Score how well isolated labels are distinguished from other
- # labels by data-driven clustering. The F1 score is used to evaluate
- # clustering with respect to the ground truth cell type labels. It returns
- # a value between 0 and 1, where 1 shows that all of the isolated label
- # cells and no others are captured in the cluster.
- # * kBET: kBET determines how well batches are mixed within a cell type. The
- # kBET algorithm determines whether the label composition of a k nearest
- # neighborhood of a cell is similar to the expected (global) label
- # composition. The test is repeated for a random subset of cells, and the
- # results are summarized as a rejection rate over all tested
- # neighborhoods. kBET score is scaled between 0 and 1 so that larger
- # scores are associated with better batch mixing.
- # * iLISI: Local inverse Simpson's Index for batch label. The metric
- # assesses whether clusters of cells in a single-cell RNA-seq dataset are
- # well-mixed across a categorical batch variable. The original iLISI score
- # ranges from 0 to the number of categories, with the latter indicating
- # good cell mixing. This is rescaled to a score between 0 and 1.
- # * cLISI: Local inverse Simpson's Index for cell type label. The metric
- # assesses whether clusters of cells in a single-cell RNA-seq dataset are
- # well-mixed across a categorical cell type variable. The original cLISI
- # score ranges from 0 to the number of categories, with the latter
- # indicating good cell mixing. This is rescaled to a score between 0
- # and 1.
- # * PCR: Principal component regression compares the explained variance by
- # batch before and after integration. The score ranges between 0 and 1.
- # The larger the score, the more different the variance contributions are
- # before and after integration.
- # * Cell cycle conservation score: Cell cycle conservation score based on
- # principle component regression on cell cycle gene scores. The cell-cycle
- # conservation score evaluates how well the cell-cycle effect can be
- # captured before and after integration. Values close to 0 indicate lower
- # conservation and 1 indicates complete conservation of the variance
- # explained by cell cycle. In other words, the variance remains unchanged
- # within each batch for complete conservation, while any deviation from
- # the preintegration variance contribution reduces the score.
- #
- # **2. Function Signature:**
- #
- # * Your `eliminate_batch_effect_fn` *must* adhere to this signature:
- #
- # ```python
- # def eliminate_batch_effect_fn(
- # adata: ad.AnnData,
- # config: dict[str, Any],
- # ) -> ad.AnnData:
- # # Your code here to return ad.AnnData without batch variation.
- # return output_data # ad.AnnData without batch variation
- # ```
- #
- # * `adata`: input ad.AnnData object containing raw gene expression counts in
- # `adata.X` field and batch labels in `adata.obs['batch']` field.
- # * `config`: Configuration parameters (dictionary for hyperparameters, etc.).
- # **Don't forget to specify parameters in this `config` dictionary.**
- #
- # * Your function **must return an ad.AnnData object** structured in the
- # following way:
- #
- # ```python
- # output_data = ad.AnnData(
- # obs=adata.obs,
- # var=adata.var,
- # obsm={
- # 'X_emb': # transformed dataset goes here.
- # },
- # )
- # ```
- #
- # **Your implementation should NOT use `cell_type` information in any way.**
- #
- # **3. Minimize use of specialized single-cell python packages.**
- #
- # There are many python packages used in single cell genomics. The only one that
- # we have installed in the coding environment is scanpy. Thus, instead of using
- # algorithms you might be tempted to use, please write your own native description
- # of these algorithms using scanpy, sklearn, numpy, scipy, tensorflow, torch, jax
- # or equivalent. There is much room to be creative in getting rid of batch
- # variation using purely native tools.
- #
- # **4. Data Set Size:**
- #
- # Please be aware that the datafile is large and if you use the wrong algorithm
- # you could OOM your sandbox or the algorithm could take a long time to run. As an
- # example, a typical matrix size is 329,762 cells × 2,000 genes.
- #
- # **5. Error Handling:**
- #
- # * The harness includes robust error handling. If your
- # `eliminate_batch_effect_fn` raises an exception, the harness will catch it,
- # log the traceback, assign a `worst_score`, and continue the evaluation. This
- # is important to ensure that a single error doesn't halt the entire process.
- # The `traceback` and any `stdout` and `stderr` output from your function are
- # captured and stored.
- # * Pay attention to the `first_traceback` in the output. This is the *first*
- # error that occurred across all the datasets.
- # * Print statements within your `eliminate_batch_effect_fn` will be captured in
- # the `stdout` and `stderr` streams. Use these judiciously for debugging.
- #
- # **6. Configuration:**
- #
- # * The `config` dictionary is passed to your `eliminate_batch_effect_fn`,
- # allowing you to parameterize your model. You should design your function to
- # utilize the values in the `config` dictionary.
- #
- # **7. Deliverable:**
- #
- # * Implement the `eliminate_batch_effect_fn` function to return an `ad.AnnData`
- # object in `X_emb` key under `obsm` annotation.
- # * Specify hyperparameters in the `config` dictionary. This dictionary will be
- # passed as an argument to your `eliminate_batch_effect_fn`.
- #
- # **8. Major advice:**
- #
- # * An expert has identified the following method as a promising candidate for
- # solving batch integration:
- # * Conditional Variational Autoencoder trained on gene expression,
- # conditioned on batch ID. Latent space explicitly split into biological
- # and batch components. Loss combines reconstruction error, KL divergence
- # for both latent components, and an adversarial loss (via gradient
- # reversal layer) penalizing batch information within the biological
- # component. Output is the batch-corrected biological latent embedding.
- # %%
- from IPython.display import clear_output
- # %%
- # Packages
- requirements = """
- anndata==0.11.3
- scanpy==1.10.4
- anndata2ri==1.3.2
- """
- with open('./requirements.in', 'w') as f:
- f.write(requirements)
- # %%
- !pip install -r ./requirements.in
- clear_output()
- # %%
- # Install scib from git to avoid GLIBC errors for lisi
- !git clone https://github.com/theislab/scib.git ./scib_source
- !cd ./scib_source && git checkout v1.1.7
- !pip install ./scib_source/
- !rm -rf ./scib_source
- clear_output()
- # %%
- %load_ext rpy2.ipython
- # %%
- %%R
- # Set global options to be non-interactive
- options(repos = c(CRAN = "https://cloud.r-project.org")) # Set a CRAN mirror
- options(pkgAsk = FALSE) # Attempt to suppress prompts globally
- # Install 'remotes' package
- # The 'ask = FALSE' argument is specific to install.packages
- install.packages('remotes', ask = FALSE)
- # Load the remotes package
- library(remotes)
- # Install 'kBET' from GitHub
- remotes::install_github('theislab/kBET', upgrade = "never")
- # %%
- import dataclasses
- import os
- import sys
- import warnings
- import anndata as ad
- from anndata.io import read_elem, sparse_dataset
- import h5py
- import numpy as np
- import pandas as pd
- import scanpy as sc
- import scib
- from scipy.sparse import csr_matrix
- INPUT_DIR = './datasets/'
- WORKING_DIR = './'
- INPUT_FILE_DIR = os.path.join(
- INPUT_DIR,
- 'single-cell-batch-integration',
- )
- INPUT_FILE_TRAIN = os.path.join(
- INPUT_FILE_DIR, 'ffdaa1f0-b1d1-4135-8774-9fed7bf039ba-train-dataset.h5ad'
- )
- INPUT_FILE_VAL = os.path.join(
- INPUT_FILE_DIR, 'ffdaa1f0-b1d1-4135-8774-9fed7bf039ba-val-dataset.h5ad'
- )
- INPUT_FILE_PRE_INTEGRATION_TRAIN = os.path.join(
- INPUT_FILE_DIR, 'ffdaa1f0-b1d1-4135-8774-9fed7bf039ba-train-solution.h5ad'
- )
- INPUT_FILE_PRE_INTEGRATION_VAL = os.path.join(
- INPUT_FILE_DIR, 'ffdaa1f0-b1d1-4135-8774-9fed7bf039ba-val-solution.h5ad'
- )
- INPUT_FILE_SCORE_BOUNDS_TRAIN = os.path.join(
- INPUT_FILE_DIR,
- 'score_train.median.bounds.csv',
- )
- INPUT_FILE_SCORE_BOUNDS_VAL = os.path.join(
- INPUT_FILE_DIR,
- 'score_val.median.bounds.csv',
- )
- # %%
- def open_h5(path: str) -> h5py.File:
- return h5py.File(path, 'r')
- # %%
- def read_anndata(
- file: str,
- backed: bool = False,
- **kwargs,
- ) -> ad.AnnData:
- """Read anndata file.
- :param file: path to anndata file in h5ad format.
- :param kwargs: AnnData parameter to group mapping.
- """
- f = open_h5(file)
- kwargs = {x: x for x in f} if not kwargs else kwargs
- if len(f.keys()) == 0:
- return ad.AnnData()
- # Check if keys are available.
- for name, slot in kwargs.items():
- if slot not in f:
- warnings.warn(
- f'Cannot find "{slot}" for AnnData parameter `{name}` from "{file}"'
- )
- adata = read_partial(f, backed=backed, **kwargs)
- if not backed:
- f.close()
- return adata
- def read_partial(
- group: h5py.Group,
- backed: bool = False,
- force_sparse_types: [str, list] = None,
- **kwargs,
- ) -> ad.AnnData:
- """Partially read h5py groups.
- :params group: file group :params force_sparse_types: encoding types to
- convert to sparse_dataset via csr_matrix. :params backed: If True, read sparse
- matrix as sparse_dataset. :params **kwargs: dict of slot_name: slot. By
- default use all available slots for the h5py file. :return: AnnData object.
- """
- if force_sparse_types is None:
- force_sparse_types = []
- elif isinstance(force_sparse_types, str):
- force_sparse_types = [force_sparse_types]
- slots = {}
- if backed:
- print('Read as backed sparse matrix...')
- for slot_name, slot in kwargs.items():
- print(f'Read slot "{slot}", store as "{slot_name}"...')
- if slot not in group:
- warnings.warn(f'Slot "{slot}" not found, skip...')
- slots[slot_name] = None
- else:
- elem = group[slot]
- iospec = ad._io.specs.get_spec(elem)
- if iospec.encoding_type in ['csr_matrix', 'csc_matrix'] and backed:
- slots[slot_name] = sparse_dataset(elem)
- elif iospec.encoding_type in force_sparse_types:
- slots[slot_name] = csr_matrix(read_elem(elem))
- if backed:
- slots[slot_name] = sparse_dataset(slots[slot_name])
- else:
- slots[slot_name] = read_elem(elem)
- return ad.AnnData(**slots)
- def dataframe_to_bounds_map(
- dataframe: pd.DataFrame,
- ) -> dict[tuple[str, str], tuple[float, float]]:
- indexed_df = dataframe.set_index(['dataset_id', 'metric_id'])
- bounds_map = {
- idx: (row['lower_bound'], row['upper_bound'])
- for idx, row in indexed_df.iterrows()
- }
- return bounds_map
- # %%
- # Input data.
- input_adata = read_anndata(
- INPUT_FILE_TRAIN,
- X='layers/counts',
- obs='obs',
- var='var',
- )
- print(input_adata)
- # %%
- # Data before integration, for computation of metrics.
- adata_pre_integration = read_anndata(
- INPUT_FILE_PRE_INTEGRATION_TRAIN,
- X='layers/normalized',
- obs='obs',
- var='var',
- uns='uns',
- )
- # Bounds for scaling of metrics, for computation of metrics.
- df_score_bounds_train = pd.read_csv(INPUT_FILE_SCORE_BOUNDS_TRAIN)
- bounds_map_train = dataframe_to_bounds_map(df_score_bounds_train)
- # We observed that isolated labels F1 is variable, thus we set [0,1] bounds
- bounds_map_train[
- ('364bd0c7-f7fd-48ed-99c1-ae26872b1042', 'isolated_label_f1')
- ] = [
- 0.0,
- 1.0,
- ]
- clear_output()
- # %%
- def subsample_adata(
- adata: ad.AnnData,
- target_size: int,
- batch_col='batch',
- celltype_col='cell_type',
- seed=42,
- ) -> ad.AnnData:
- """Subsamples ad.AnnData object while maintaining the distribution of batches and cell types.
- Args:
- adata (ad.AnnData): The AnnData object to subsample.
- target_size (int): The desired number of observations in the subsampled
- AnnData.
- batch_col (str): The column in adata.obs containing batch information.
- celltype_col (str): The column in adata.obs containing cell type
- information.
- seed (int): Random seed for reproducibility.
- Returns:
- ad.AnnData: The subsampled AnnData object.
- """
- np.random.seed(seed)
- obs = adata.obs[[batch_col, celltype_col]].copy()
- obs['index'] = obs.index
- # Calculate the desired proportions for each group
- group_counts = obs.groupby([batch_col, celltype_col], observed=True).size()
- total_counts = len(adata)
- group_proportions = group_counts / total_counts
- # Calculate the number of samples to take from each group
- group_sample_sizes = (group_proportions * target_size).astype(int)
- # Adjust sample sizes to match the target size as closely as possible
- remaining = target_size - group_sample_sizes.sum()
- if remaining != 0:
- sorted_groups = group_proportions.sort_values(ascending=False).index
- for group in sorted_groups:
- if remaining > 0:
- group_sample_sizes[group] += 1
- remaining -= 1
- elif remaining < 0:
- if group_sample_sizes[group] > 0:
- group_sample_sizes[group] -= 1
- remaining += 1
- if remaining == 0:
- break
- # Subsample each group
- sampled_indices = []
- for group, size in group_sample_sizes.items():
- group_indices = obs[
- (obs[batch_col] == group[0]) & (obs[celltype_col] == group[1])
- ]['index'].values
- sampled_indices.extend(
- np.random.choice(group_indices, size=size, replace=False)
- )
- # Create the subsampled AnnData object
- subsampled_adata = adata[sampled_indices, :].copy()
- return subsampled_adata
- # %%
- # Subsample data.
- input_adata = subsample_adata(input_adata, target_size=20000, seed=42)
- # Apply subsampling to pre-integrated data for metrics.
- adata_pre_integration = adata_pre_integration[input_adata.obs.index, :]
- print(input_adata)
- # %% [markdown]
- # # Evaluation
- # %%
- CONTROL_METHODS = [
- 'embed_cell_types',
- 'embed_cell_types_jittered',
- 'no_integration',
- 'no_integration_batch',
- 'shuffle_integration',
- 'shuffle_integration_by_batch',
- 'shuffle_integration_by_cell_type',
- ]
- DATASET_ID = adata_pre_integration.uns['dataset_id']
- METHOD_ID = 'scagent'
- @dataclasses.dataclass(frozen=True)
- class Result:
- dataset_id: str
- method_id: str
- metric_id: str
- value: float
- @property
- def is_control_method(self):
- return self.method_id in CONTROL_METHODS
- def scaled(self, bounds: dict[tuple[str, str], tuple[float, float]]):
- """Returns a new Result with the value scaled to the bounds."""
- lower_bound, upper_bound = bounds[(self.dataset_id, self.metric_id)]
- if (
- np.isnan(lower_bound)
- or np.isnan(upper_bound)
- or lower_bound >= upper_bound
- ):
- scaled_value = np.nan
- else:
- scaled_value = (self.value - lower_bound) / (upper_bound - lower_bound)
- return dataclasses.replace(self, value=scaled_value)
- def run_leiden_clustering(adata: ad.AnnData, resolution: float) -> ad.AnnData:
- # Based on
- # https://github.com/openproblems-bio/task_batch_integration/blob/main/src/data_processors/precompute_clustering_run/script.py
- from scanpy.tl import leiden
- key = f'leiden_{resolution}'
- kwargs = {'flavor': 'igraph', 'n_iterations': 2}
- leiden(
- adata,
- resolution=resolution,
- key_added=key,
- **kwargs,
- )
- return adata
- def score(
- adata: ad.AnnData,
- adata_pre_integration: ad.AnnData,
- bounds_map: dict[tuple[str, str], tuple[float, float]],
- dataset_id: str = DATASET_ID,
- method_id: str = METHOD_ID,
- ) -> float:
- # Suppress warnings just for scoring.
- with warnings.catch_warnings():
- warnings.filterwarnings('ignore', category=FutureWarning)
- warnings.filterwarnings('ignore', category=UserWarning)
- warnings.filterwarnings('ignore', category=DeprecationWarning)
- warnings.filterwarnings('ignore', category=RuntimeWarning)
- # Preprocess data - compute kNN.
- if 'X_emb' in adata.obsm and 'neighbors' not in adata.uns:
- sc.pp.neighbors(adata, use_rep='X_emb')
- # Preprocess data - compute clusterings at different resolutions.
- # Based on
- # https://github.com/openproblems-bio/task_batch_integration/blob/main/src/data_processors/process_integration/config.vsh.yaml
- resolutions = [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
- for resolution in resolutions:
- adata = run_leiden_clustering(adata, resolution)
- # Based on
- # https://github.com/openproblems-bio/task_batch_integration/blob/main/src/metrics/clustering_overlap/script.py
- cluster_key = 'leiden'
- scib.metrics.clustering.cluster_optimal_resolution(
- adata=adata,
- label_key='cell_type',
- cluster_key=cluster_key,
- cluster_function=sc.tl.leiden,
- resolutions=resolutions,
- verbose=False,
- )
- # Compute metrics.
- asw_batch = scib.metrics.silhouette_batch(
- adata,
- batch_key='batch',
- label_key='cell_type',
- embed='X_emb',
- verbose=False,
- )
- print(f'ASW batch: {asw_batch}')
- asw_label = scib.metrics.silhouette(
- adata, label_key='cell_type', embed='X_emb'
- )
- print(f'ASW label: {asw_label}')
- ari_score = scib.metrics.ari(
- adata, cluster_key=cluster_key, label_key='cell_type'
- )
- print(f'ARI: {ari_score}')
- nmi_score = scib.metrics.nmi(
- adata, cluster_key=cluster_key, label_key='cell_type'
- )
- print(f'NMI: {nmi_score}')
- graph_connectivity = scib.metrics.graph_connectivity(
- adata, label_key='cell_type'
- )
- print(f'Graph connectivity: {graph_connectivity}')
- isolated_labels_asw = scib.metrics.isolated_labels_asw(
- adata,
- label_key='cell_type',
- batch_key='batch',
- embed='X_emb',
- iso_threshold=None,
- verbose=False,
- )
- print(f'Isolated labels ASW: {isolated_labels_asw}')
- isolated_labels_f1 = scib.metrics.isolated_labels_f1(
- adata,
- label_key='cell_type',
- batch_key='batch',
- cluster_key='leiden',
- resolutions=resolutions,
- embed=None,
- iso_threshold=None,
- verbose=False,
- )
- print(f'Isolated labels F1: {isolated_labels_f1}')
- # kBET
- kbet_score = scib.metrics.kBET(
- adata,
- batch_key='batch',
- label_key='cell_type',
- type_='embed',
- embed='X_emb',
- scaled=True,
- verbose=False,
- )
- print(f'kBET: {kbet_score}')
- # iLISI
- ilisi_scores = scib.metrics.lisi.lisi_graph_py(
- adata=adata,
- obs_key='batch',
- n_neighbors=90,
- perplexity=None,
- subsample=None,
- n_cores=1,
- verbose=False,
- )
- ilisi = np.nanmedian(ilisi_scores)
- ilisi = (ilisi - 1) / (adata.obs['batch'].nunique() - 1)
- print(f'iLISI: {ilisi}')
- # cLISI scores
- clisi_scores = scib.metrics.lisi.lisi_graph_py(
- adata=adata,
- obs_key='cell_type',
- n_neighbors=90,
- perplexity=None,
- subsample=None,
- n_cores=1,
- verbose=False,
- )
- clisi = np.nanmedian(clisi_scores)
- nlabs = adata.obs['cell_type'].nunique()
- clisi = (nlabs - clisi) / (nlabs - 1)
- print(f'cLISI: {clisi}')
- # PCR
- adata_integrated = adata.copy()
- adata_integrated.obs['batch'] = adata_pre_integration.obs['batch']
- pcr_score = scib.metrics.pcr_comparison(
- adata_pre_integration[:, adata_pre_integration.var['batch_hvg']],
- adata_integrated,
- embed='X_emb',
- covariate='batch',
- verbose=False,
- )
- print(f'PCR: {pcr_score}')
- # Cell cycle (compute this last since the var_names is updated)
- adata_pre_integration.var_names = adata_pre_integration.var['feature_name']
- adata_pre_integration.var_names = adata_pre_integration.var_names.astype(
- str
- )
- cell_cycle_score = scib.metrics.cell_cycle(
- adata_pre_integration,
- adata_integrated,
- batch_key='batch',
- embed='X_emb',
- organism=adata_pre_integration.uns['dataset_organism'],
- verbose=False,
- )
- print(f'Cell cycle conservation score: {cell_cycle_score}')
- scores = {
- 'asw_label': asw_label,
- 'asw_batch': asw_batch,
- 'ari': ari_score,
- 'nmi': nmi_score,
- 'graph_connectivity': graph_connectivity,
- 'isolated_label_asw': isolated_labels_asw,
- 'isolated_label_f1': isolated_labels_f1,
- 'kbet': kbet_score,
- 'ilisi': ilisi,
- 'clisi': clisi,
- 'pcr': pcr_score,
- 'cell_cycle_conservation': cell_cycle_score,
- }
- # Scale metrics using lower and upper bounds.
- scaled_scores = []
- for metric_id, value in scores.items():
- unscaled_score = Result(
- dataset_id=dataset_id,
- method_id=method_id,
- metric_id=metric_id,
- value=value,
- )
- scaled_score = unscaled_score.scaled(bounds_map)
- scaled_scores.append(scaled_score)
- df = pd.DataFrame(
- [dataclasses.asdict(score) for score in scaled_scores]
- ).fillna(0)
- # Perform clipping.
- df.value = df.value.clip(0, 1)
- print('Metrics after scaling and clipping:')
- print(df[['metric_id', 'value']])
- avg_score = df['value'].mean()
- return avg_score
- # %%
- # [exclude_from_prompt]
- from sklearn.decomposition import TruncatedSVD
- # Test on small subset:
- # Generate random unique indices for cells.
- random_cell_indices = np.random.choice(
- input_adata.shape[0], size=100, replace=False
- )
- small_adata = input_adata[random_cell_indices, :].copy()
- small_adata_pre_integration = adata_pre_integration[
- random_cell_indices, :
- ].copy()
- # Normalize to median total counts.
- sc.pp.normalize_total(small_adata)
- # Log transform the data.
- sc.pp.log1p(small_adata)
- X_input = small_adata.X
- n_components = 2
- pca = TruncatedSVD(n_components=n_components)
- X_output = pca.fit_transform(X_input)
- output = ad.AnnData(
- obs=small_adata.obs,
- var=small_adata.var,
- obsm={
- "X_emb": X_output,
- },
- )
- score(output, small_adata_pre_integration, bounds_map_train)
- # %% [markdown]
- # # Begin mutable cells
- # %%
- from typing import Any
- import jax
- from sklearn.decomposition import TruncatedSVD
- import tensorflow as tf
- import torch
- # Define parameters for the config.
- config = {}
- def eliminate_batch_effect_fn(
- adata: ad.AnnData, config: dict[str, Any]
- ) -> ad.AnnData:
- # Your code here to return ad.AnnData without batch variation.
- # %% [markdown]
- # # End mutable cells
- # %% [markdown]
- # # Validation
- # %%
- cell_type_info = input_adata.obs.pop('cell_type')
- output_adata = eliminate_batch_effect_fn(input_adata, config=config)
- output_adata.obs['cell_type'] = cell_type_info
- # %%
- validation_score = score(output_adata, adata_pre_integration, bounds_map_train)
- print(f'Validation Score: {validation_score}')
- # %%
- # [exclude_from_prompt]
- # Calculate scores based on the fixed validation set.
- if False:
- # Input data.
- input_adata_val = read_anndata(
- INPUT_FILE_VAL,
- X='layers/counts',
- obs='obs',
- var='var',
- )
- print(input_adata_val)
- # Data before integration, for computation of metrics.
- adata_pre_integration_val = read_anndata(
- INPUT_FILE_PRE_INTEGRATION_VAL,
- X='layers/normalized',
- obs='obs',
- var='var',
- uns='uns',
- )
- print(adata_pre_integration_val)
- # Bounds for scaling of metrics, for computation of metrics.
- df_score_bounds_val = pd.read_csv(INPUT_FILE_SCORE_BOUNDS_VAL)
- bounds_map_val = dataframe_to_bounds_map(df_score_bounds_val)
- cell_type_info_val = input_adata_val.obs.pop('cell_type')
- output_adata_val = eliminate_batch_effect_fn(input_adata_val, config=config)
- output_adata_val.obs['cell_type'] = cell_type_info_val
- validation_score_val = score(
- output_adata_val, adata_pre_integration_val, bounds_map_val
- )
- print(
- 'Validation Score (calculated using validation set):'
- f' {validation_score_val}'
- )
- # %%
- # [exclude_from_prompt]
- # Calculate scores based on the test set.
- if False:
- import time
- TEST_DATASETS = [
- 'dkd',
- 'gtex_v9',
- 'hypomap',
- 'immune_cell_atlas',
- 'mouse_pancreas_atlas',
- 'tabula_sapiens',
- ]
- INPUT_FILE_TEST_PATTERN = os.path.join(
- INPUT_FILE_DIR, '{dataset}-subsampled-dataset.h5ad'
- )
- INPUT_FILE_PRE_INTEGRATION_TEST_PATTERN = os.path.join(
- INPUT_FILE_DIR, '{dataset}-subsampled-solution.h5ad'
- )
- INPUT_BOUND_TEST = './datasets/single-cell-batch-integration/openproblems_metrics_bounds.csv'
- def evaluate_on_test(
- input_dataset: ad.AnnData,
- input_solution: ad.AnnData,
- input_bounds: pd.DataFrame,
- dataset_id: str,
- method_id: str = METHOD_ID,
- ) -> int:
- bounds_map = dataframe_to_bounds_map(df_score_bounds)
- cell_type_info_val = input_dataset.obs.pop('cell_type')
- try:
- output_adata = eliminate_batch_effect_fn(input_dataset, config=config)
- output_adata.obs['cell_type'] = cell_type_info_val
- validation_score = score(
- output_adata, input_solution, bounds_map, dataset_id, method_id
- )
- except Exception as e:
- print(f"Error during evaluating dataset {dataset_id}: {e}")
- validation_score = None
- return validation_score
- all_validation_scores = []
- for dataset_name in TEST_DATASETS:
- print(f'========Start evaluation on {dataset_name} dataset ========')
- print(f'========Reading {dataset_name} dataset from file ========')
- start = time.time()
- # Input data.
- input_adata = read_anndata(
- INPUT_FILE_TEST_PATTERN.format(dataset=dataset_name),
- X='layers/counts',
- obs='obs',
- var='var',
- )
- # Data before integration, for computation of metrics.
- adata_pre_integration = read_anndata(
- INPUT_FILE_PRE_INTEGRATION_TEST_PATTERN.format(dataset=dataset_name),
- X='layers/normalized',
- obs='obs',
- var='var',
- uns='uns',
- )
- t = time.time() - start
- print(
- f'========Finished loading {dataset_name} dataset. Took'
- f' {t} seconds.========'
- )
- # Bounds for scaling of metrics, for computation of metrics.
- df_score_bounds = pd.read_csv(INPUT_BOUND_TEST)
- print(f'========Scoring {dataset_name} dataset ========')
- start = time.time()
- validation_score = evaluate_on_test(
- input_dataset=input_adata,
- input_solution=adata_pre_integration,
- input_bounds=df_score_bounds,
- dataset_id=f'cellxgene_census/{dataset_name}',
- )
- t = time.time() - start
- print(f'========Finished scoring. Took {t} seconds.========')
- print(
- f'Validation Score (calculated using {dataset_name} set):'
- f' {validation_score}'
- )
- all_validation_scores.append(validation_score)
- # --- Calculate the two averages ---
- # 1. Average imputing None as 0
- scores_imputed_as_zero = [s if s is not None else 0 for s in all_validation_scores]
- average_imputed_zero = sum(scores_imputed_as_zero) / len(scores_imputed_as_zero)
- print(f'\n======== Average Validation Score (imputing None as 0): {average_imputed_zero:.4f} ========')
- # 2. Average only across available datasets (excluding None)
- available_scores = [s for s in all_validation_scores if s is not None]
- if available_scores: # Avoid division by zero if all scores are None
- average_available = sum(available_scores) / len(available_scores)
- print(f'======== Average Validation Score (only available datasets): {average_available:.4f} ========')
- else:
- print('======== No available validation scores to calculate average for available datasets. ========')
- # %%
single_cell_batch_integration.ipynb at commit b836730, under Apache-2.0 · at the source
Overview
and 22 other authors
Qian-Ze Zhu2,5, Matthew Abraham2, Erica Brand2, Anna Bulanova1, Jeffrey A. Cardille2,7, Chris Co2, Scott Ellsworth2, Grace Joseph2, Malcolm Kane2, Ryan Krueger2,5, Johan Kartiwa2, Dan Liebling2, Jan-Matthis Lueckmann2, Paul Raccuglia2, Xuefei Julie Wang2,8, Katherine Chou2, James Manyika2, Yossi Matias2, John C. Platt2, Lizzie Dorfman2, Shibl Mourad1, Michael P. Brenner2,5- Google DeepMind, Montréal, Quebec Canada
- Google Research,Cambridge, MA USA
- Google Platforms and Devices, Mountain View, CA USA
- Massachusetts Institute of Technology,Cambridge, MA USA
- School of Engineering and Applied Sciences, Harvard University,Cambridge, MA USA
- Google DeepMind, New York, NY USA
- Faculty of Agricultural and Environmental Sciences, McGill University,Montréal, Quebec Canada
- California Institute of Technology,Pasadena, CA USA
Abstract
The cycle of scientific discovery is frequently bottlenecked by the slow, manual creation of software to support computational experiments1. To address this, we present Empirical Research Assistance (ERA), an artificial intelligence (AI) system that creates expert-level scientific software whose goal is to maximize a quality metric. The system uses a large language model (LLM) and tree search2 to systematically improve the quality metric and intelligently navigate the large space of possible solutions. ERA achieves expert-level results when it explores and integrates complex research ideas from external sources. The effectiveness of tree search is demonstrated across a diverse range of tasks. In bioinformatics, ERA discovered 40 new methods for single-cell data analysis that outperformed the top human-developed methods on a public leaderboard. In epidemiology, ERA generated 14 models that outperformed the Centers for Disease Control and Prevention (CDC) ensemble and all other individual models for forecasting COVID-19 hospitalizations. ERA also produced expert-level software for geospatial analysis, neural activity prediction in zebrafish and numerical solution of integrals, as well as a new rule-based construction for time-series forecasting. By devising and implementing new solutions to diverse tasks, ERA represents a notable step towards accelerating scientific progress.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 11 matches between paragraphs and lines of code.
salesforceairesearch/gift-eval
733645d21c9428cd249761b6ce2f3098f59b2f01, 28 September 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
53 files
- cli/
__init__.py , Python, 1 line - cli/
analysis.py , Python, 32 lines - notebooks/
CleanTS.ipynb , Jupyter, 205 lines - notebooks/
Credence.ipynb , Jupyter, 358 lines - notebooks/
caststar.ipynb , Jupyter, 1,028 lines - notebooks/
chronos-2.ipynb , Jupyter, 322 lines - notebooks/
chronos.ipynb , Jupyter, 346 lines - notebooks/
dataset.ipynb , Jupyter, 152 lines - notebooks/
dlinear_t.ipynb , Jupyter, 358 lines - notebooks/
falcon-2.ipynb , Jupyter, 581 lines - notebooks/
falcon-x.ipynb , Jupyter, 499 lines - notebooks/
feedforward.ipynb , Jupyter, 208 lines - notebooks/
flowstate.ipynb , Jupyter, 329 lines - notebooks/
kairos.ipynb , Jupyter, 408 lines - notebooks/
litespecformer.ipynb , Jupyter, 333 lines - notebooks/
moirai.ipynb , Jupyter, 226 lines - notebooks/
moirai2.ipynb , Jupyter, 297 lines - notebooks/
naive.ipynb , Jupyter, 437 lines - notebooks/
patchfm.ipynb , Jupyter, 315 lines - notebooks/
patchtst_fm.ipynb , Jupyter, 300 lines - notebooks/
patchtst_fm_r2.ipynb , Jupyter, 286 lines - notebooks/
sundial.ipynb , Jupyter, 319 lines - notebooks/
super_linear.ipynb , Jupyter, 399 lines - notebooks/
t0-alpha.ipynb , Jupyter, 293 lines - notebooks/
t0-beta.ipynb , Jupyter, 293 lines - notebooks/
tabpfn_ts.ipynb , Jupyter, 271 lines - notebooks/
tafsut.ipynb , Jupyter, 445 lines - notebooks/
timecopilot.ipynb , Jupyter, 230 lines - notebooks/
timer-s1.ipynb , Jupyter, 288 lines - notebooks/
timesfm.ipynb , Jupyter, 349 lines - notebooks/
timesfm2p5.ipynb , Jupyter, 313 lines - notebooks/
timesfm3.ipynb , Jupyter, 420 lines - notebooks/
tirex-2.ipynb , Jupyter, 583 lines - notebooks/
tirex.ipynb , Jupyter, 434 lines - notebooks/
toto.ipynb , Jupyter, 734 lines - notebooks/
toto_2_0.ipynb , Jupyter, 160 lines - notebooks/
toto_2_0_fnf.ipynb , Jupyter, 782 lines - notebooks/
ttm.ipynb , Jupyter, 416 lines - notebooks/
ttm_r3.ipynb , Jupyter, 526 lines - notebooks/
yinglong.ipynb , Jupyter, 480 lines - notebooks/
zeus.ipynb , Jupyter, 337 lines - scripts/
validate_results.py , Python, 321 lines, 1 match - src/
__init__.py , Python, 15 lines - src/
gift_eval/ , Python, 16 lines__about__.py - src/
gift_eval/ , Python, 15 lines__init__.py - src/
gift_eval/ , Python, 3 linesanalysis/ __init__.py - src/
gift_eval/ , Python, 242 linesanalysis/ analyzer.py - src/
gift_eval/ , Python, 101 linesanalysis/ features.py - src/
gift_eval/ , Python, 139 linesanalysis/ utils.py - src/
gift_eval/ , Python, 241 linesdata.py - tests/
test_validate_results.py , Python, 217 lines - LICENSE.txt, License, 206 lines
- README.md, Text, 256 lines
google-research/era
b836730b5c000526af95116b1d0e2c60c8cf0a10, 3 August 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
11 files
- docs/
static/ , JavaScript, 353 linesstudy_js.js - implementation/
experiment_pipeline.ipyn , Jupyter, 176 linesb - implementation/
futs.py , Python, 155 lines, 3 matches - implementation/
futs_test.py , Python, 139 lines - implementation/
llm.py , Python, 49 lines - implementation/
notebooks/ , Jupyter, 755 lines, 2 matchesflu-cornell-jhu-hierarch sir.ipynb - implementation/
notebooks/ , Jupyter, 968 lines, 4 matchessingle_cell_batch_integr ation.ipynb - implementation/
playground_s3e1.py , Python, 278 lines, 1 match - implementation/
sandbox.py , Python, 35 lines - LICENSE, License, 202 lines
- README.md, Text, 101 lines
Code availability
A reference implementation of ERA is available at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 60 scripts, each with its path and the digest of its content;
- 11 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- google-research.github.i
o/ , at google-research.github.io; found in “Code availability”era - huggingface.co/
datasets/ , at Hugging Face; found in the text, “GIFT-Eval benchmark”salesforce/ gifteval
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 2, 28 September 2026
- Publisher: n/a → Nature Portfolio
Version 1, 28 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 42 authors, 2 keywords, 12 MeSH terms, 35 references.
Cite
This paper
Aygün, E., Belyaeva, A., Comanici, G., Coram, M., Cui, H., Garrison, J., Johnston, R., Kast, A., McLean, C. Y., Norgaard, P., Shamsi, Z., Smalling, D., Thompson, J., Venugopalan, S., Williams, B. P., He, C., Martinson, S., Plomecka, M., Wei, L., . . . Brenner, M. P. (2026). An AI system to help scientists write expert-level empirical software. Nature, 654(8120), 909-916. https://
BibTeX
@article{aygun2026ai,
author = {Aygün, Eser and Belyaeva, Anastasiya and Comanici, Gheorghe and Coram, Marc and Cui, Hao and Garrison, Jake and Johnston, Renee and Kast, Anton and McLean, Cory Y. and Norgaard, Peter and Shamsi, Zahra and Smalling, David and Thompson, James and Venugopalan, Subhashini and Williams, Brian P. and He, Chujun and Martinson, Sarah and Plomecka, Martyna and Wei, Lai and Zhou, Yuchen and Zhu, Qian-Ze and Abraham, Matthew and Brand, Erica and Bulanova, Anna and Cardille, Jeffrey A. and Co, Chris and Ellsworth, Scott and Joseph, Grace and Kane, Malcolm and Krueger, Ryan and Kartiwa, Johan and Liebling, Dan and Lueckmann, Jan-Matthis and Raccuglia, Paul and Wang, Xuefei Julie and Chou, Katherine and Manyika, James and Matias, Yossi and Platt, John C. and Dorfman, Lizzie and Mourad, Shibl and Brenner, Michael P.},
title = {{An AI system to help scientists write expert-level empirical software}},
journal = {Nature},
year = {2026},
month = may,
volume = {654},
number = {8120},
pages = {909--916},
publisher = {Nature Portfolio},
issn = {0028-0836},
doi = {10.1038/
url = {https://
pmid = {42156545},
pmcid = {PMC13293872}
}
RIS
TY - JOUR
AU - Aygün, Eser
AU - Belyaeva, Anastasiya
AU - Comanici, Gheorghe
AU - Coram, Marc
AU - Cui, Hao
AU - Garrison, Jake
AU - Johnston, Renee
AU - Kast, Anton
AU - McLean, Cory Y.
AU - Norgaard, Peter
AU - Shamsi, Zahra
AU - Smalling, David
AU - Thompson, James
AU - Venugopalan, Subhashini
AU - Williams, Brian P.
AU - He, Chujun
AU - Martinson, Sarah
AU - Plomecka, Martyna
AU - Wei, Lai
AU - Zhou, Yuchen
AU - Zhu, Qian-Ze
AU - Abraham, Matthew
AU - Brand, Erica
AU - Bulanova, Anna
AU - Cardille, Jeffrey A.
AU - Co, Chris
AU - Ellsworth, Scott
AU - Joseph, Grace
AU - Kane, Malcolm
AU - Krueger, Ryan
AU - Kartiwa, Johan
AU - Liebling, Dan
AU - Lueckmann, Jan-Matthis
AU - Raccuglia, Paul
AU - Wang, Xuefei Julie
AU - Chou, Katherine
AU - Manyika, James
AU - Matias, Yossi
AU - Platt, John C.
AU - Dorfman, Lizzie
AU - Mourad, Shibl
AU - Brenner, Michael P.
TI - An AI system to help scientists write expert-level empirical software
T2 - Nature
J2 - Nature
PY - 2026
DA - 2026/
VL - 654
IS - 8120
SP - 909
EP - 916
SN - 0028-0836
PB - Nature Portfolio
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "An AI system to help scientists write expert-level empirical software",
"container-title": "Nature",
"author": [
{
"family": "Aygün",
"given": "Eser"
},
{
"family": "Belyaeva",
"given": "Anastasiya"
},
{
"family": "Comanici",
"given": "Gheorghe"
},
{
"family": "Coram",
"given": "Marc"
},
{
"family": "Cui",
"given": "Hao"
},
{
"family": "Garrison",
"given": "Jake"
},
{
"family": "Johnston",
"given": "Renee"
},
{
"family": "Kast",
"given": "Anton"
},
{
"family": "McLean",
"given": "Cory Y."
},
{
"family": "Norgaard",
"given": "Peter"
},
{
"family": "Shamsi",
"given": "Zahra"
},
{
"family": "Smalling",
"given": "David"
},
{
"family": "Thompson",
"given": "James"
},
{
"family": "Venugopalan",
"given": "Subhashini"
},
{
"family": "Williams",
"given": "Brian P."
},
{
"family": "He",
"given": "Chujun"
},
{
"family": "Martinson",
"given": "Sarah"
},
{
"family": "Plomecka",
"given": "Martyna"
},
{
"family": "Wei",
"given": "Lai"
},
{
"family": "Zhou",
"given": "Yuchen"
},
{
"family": "Zhu",
"given": "Qian-Ze"
},
{
"family": "Abraham",
"given": "Matthew"
},
{
"family": "Brand",
"given": "Erica"
},
{
"family": "Bulanova",
"given": "Anna"
},
{
"family": "Cardille",
"given": "Jeffrey A."
},
{
"family": "Co",
"given": "Chris"
},
{
"family": "Ellsworth",
"given": "Scott"
},
{
"family": "Joseph",
"given": "Grace"
},
{
"family": "Kane",
"given": "Malcolm"
},
{
"family": "Krueger",
"given": "Ryan"
},
{
"family": "Kartiwa",
"given": "Johan"
},
{
"family": "Liebling",
"given": "Dan"
},
{
"family": "Lueckmann",
"given": "Jan-Matthis"
},
{
"family": "Raccuglia",
"given": "Paul"
},
{
"family": "Wang",
"given": "Xuefei Julie"
},
{
"family": "Chou",
"given": "Katherine"
},
{
"family": "Manyika",
"given": "James"
},
{
"family": "Matias",
"given": "Yossi"
},
{
"family": "Platt",
"given": "John C."
},
{
"family": "Dorfman",
"given": "Lizzie"
},
{
"family": "Mourad",
"given": "Shibl"
},
{
"family": "Brenner",
"given": "Michael P."
}
],
"container-title-short":
"volume": "654",
"issue": "8120",
"page": "909-916",
"DOI": "10.1038/
"PMID": "42156545",
"PMCID": "PMC13293872",
"ISSN": "0028-0836",
"publisher": "Nature Portfolio",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
19
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1093/nar/gkag706 [code]
- scDifformer: diffusion-based post-training for virtual cell modeling across large-scale single-cell data.Journal: Nucleic acids researchIn common: anndata, Scanpy, TensorFlow, 7 other tools, 3 references
- [2] doi:10.1038/s42003-026-10957-8 [code]
- Brain defence by the extracellular matrix protein Cochlin.Journal: Communications biologyIn common: JAX, Hugging Face Transformers, XGBoost, 7 other tools, zebrafish
- [3] doi:10.1038/s41592-026-03194-8 [code]
- Beyond benchmarking: an expert-guided consensus approach to spatially aware clustering.Journal: Nature methodsIn common: anndata, Scanpy, TensorFlow, 6 other tools, methods / tools, 2 references
- [4] doi:10.1038/s41592-026-03057-2 [code]
- CREsted: modeling genomic and synthetic cell-type-specific enhancers across tissues and species.Journal: Nature methodsIn common: anndata, Scanpy, TensorFlow, 7 other tools, zebrafish, methods / tools
- [5] doi:10.1038/s44320-026-00208-7 [code]
- Interpretable deep generative ensemble learning for single-cell omics with Hydra.Journal: Molecular systems biologyIn common: anndata, Scanpy, TensorFlow, 7 other tools, 1 reference
- [6] doi:10.1093/bib/bbag490 [code]
- Systematic benchmarking and optimal strategy selection of cross-species integration methods.Journal: Briefings in bioinformaticsIn common: anndata, Scanpy, scikit-learn, 4 other tools, methods / tools, 3 references
- [7] doi:10.1186/s12859-026-06490-4 [code]
- Tissueformer: extending single-cell foundation models to predict population-level phenotypes.Journal: BMC bioinformaticsIn common: Hugging Face Transformers, anndata, PyTorch, 5 other tools, other condition, 2 references
- [8] doi:10.1038/s41598-026-48613-0 [code]
- An snRNA-seq aging clock for the fruit fly head sheds light on sex-biased aging.Journal: Scientific reportsIn common: XGBoost, anndata, Scanpy, 7 other tools
- [9] doi:10.1186/s12864-026-12965-8 [code]
- Systematic evaluation of single-cell foundation model interpretability: attention-derived edge scores add no incremental value over gene-level features for perturbation-target prediction.Journal: BMC genomicsIn common: Hugging Face Transformers, anndata, Scanpy, 7 other tools
- [10] doi:10.64898/2026.03.30.714220 [code]
- An integrated single cell and spatial omics atlas of human prenatal developmentJournal: bioRxiv (preprint)In common: Hugging Face Transformers, anndata, Scanpy, 7 other tools
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 60 scripts, and 11 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:26611141b1f4219f…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
