Skip to content

Commit fe6dd11

Browse files
authored
Add random_labels negative control (#22)
* add random_labels control method * seed np.random in process_dataset * write metric_values as a list * update changelog
1 parent 8f952fc commit fe6dd11

7 files changed

Lines changed: 103 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
* Added `metrics/accuracy` component (PR #5).
1616

17+
* Added `control_methods/random_labels` component (PR #22).
18+
1719
## MAJOR CHANGES
1820

1921
* Updated `api` files (PR #5).
@@ -43,3 +45,7 @@
4345

4446
## BUGFIXES
4547

48+
* `process_dataset`: also seed `np.random` when `--seed` is set (PR #22).
49+
50+
* `accuracy`: write `metric_values` as a list to match `metric_ids` (PR #22).
51+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# The API specifies which type of component this is.
2+
# It contains specifications for:
3+
# - The input/output files
4+
# - Common parameters
5+
# - A unit test
6+
__merge__: ../../api/comp_control_method.yaml
7+
8+
# A unique identifier for your component (required).
9+
# Can contain only lowercase letters or underscores.
10+
name: random_labels
11+
12+
# A relatively short label, used when rendering visualisations (required)
13+
label: Random Labels
14+
# A one sentence summary of how this method works (required). Used when
15+
# rendering summary tables.
16+
summary: "a negative control, where the labels are randomly predicted."
17+
# A multi-line description of how this component works (required). Used
18+
# when rendering reference documentation.
19+
description: |
20+
A negative control, where the labels are randomly predicted based on the
21+
label distribution of the training data, without looking at the input data.
22+
23+
# Metadata for your component
24+
info:
25+
# Which normalisation method this component prefers to use (required).
26+
preferred_normalization: counts
27+
28+
# Resources required to run the component
29+
resources:
30+
# The script of your component (required)
31+
- type: python_script
32+
path: script.py
33+
34+
engines:
35+
# Specifications for the Docker image for this component.
36+
- type: docker
37+
image: openproblems/base_python:1
38+
39+
runners:
40+
# This platform allows running the component natively
41+
- type: executable
42+
# Allows turning the component into a Nextflow module / pipeline.
43+
- type: nextflow
44+
directives:
45+
label: [midtime, lowmem, lowcpu]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import anndata as ad
2+
import numpy as np
3+
4+
## VIASH START
5+
# Note: this section is auto-generated by viash at runtime. To edit it, make changes
6+
# in config.vsh.yaml and then run `viash config inject config.vsh.yaml`.
7+
par = {
8+
'input_train': 'resources_test/task_template/cxg_mouse_pancreas_atlas/train.h5ad',
9+
'input_test': 'resources_test/task_template/cxg_mouse_pancreas_atlas/test.h5ad',
10+
'input_solution': 'resources_test/task_template/cxg_mouse_pancreas_atlas/solution.h5ad',
11+
'output': 'output.h5ad'
12+
}
13+
meta = {
14+
'name': 'random_labels'
15+
}
16+
## VIASH END
17+
18+
print('Reading input files', flush=True)
19+
input_train = ad.read_h5ad(par['input_train'])
20+
input_test = ad.read_h5ad(par['input_test'])
21+
22+
print('Compute label distribution', flush=True)
23+
label_distribution = input_train.obs["label"].value_counts()
24+
label_distribution = label_distribution / label_distribution.sum()
25+
26+
print('Generate predictions', flush=True)
27+
obs_label_pred = np.random.choice(
28+
label_distribution.index,
29+
size=input_test.n_obs,
30+
replace=True,
31+
p=label_distribution
32+
)
33+
34+
print("Write output AnnData to file", flush=True)
35+
output = ad.AnnData(
36+
uns={
37+
'dataset_id': input_train.uns['dataset_id'],
38+
'normalization_id': input_train.uns['normalization_id'],
39+
'method_id': meta['name']
40+
},
41+
obs={
42+
'label_pred': obs_label_pred
43+
}
44+
)
45+
output.obs_names = input_test.obs_names
46+
47+
output.write_h5ad(par['output'], compression='gzip')

src/data_processors/process_dataset/script.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
config = op.project.read_viash_config(meta["config"])
2929

3030
# set seed if need be
31-
if par["seed"]:
31+
if par["seed"] is not None:
3232
print(f">> Setting seed to {par['seed']}")
3333
random.seed(par["seed"])
34+
np.random.seed(par["seed"])
3435

3536
print(">> Load data", flush=True)
3637
adata = ad.read_h5ad(par["input"])

src/metrics/accuracy/script.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
# metric_ids and metric_values can have length > 1
3333
# but should be of equal length
3434
uns_metric_ids = [ 'accuracy' ]
35-
uns_metric_values = np.mean(input_solution.obs["label"] == input_prediction.obs["label_pred"])
35+
uns_metric_values = [ np.mean(input_solution.obs["label"] == input_prediction.obs["label_pred"]) ]
3636

3737
print("Write output AnnData to file", flush=True)
3838
output = ad.AnnData(

src/workflows/run_benchmark/config.vsh.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ dependencies:
9696
- name: utils/extract_uns_metadata
9797
repository: openproblems
9898
- name: control_methods/true_labels
99+
- name: control_methods/random_labels
99100
- name: methods/logistic_regression
100101
- name: metrics/accuracy
101102

src/workflows/run_benchmark/main.nf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ workflow auto {
1010
// construct list of methods and control methods
1111
methods = [
1212
true_labels,
13+
random_labels,
1314
logistic_regression
1415
]
1516

0 commit comments

Comments
 (0)