Candidate Selection API¶
Signature-based shortlist generation (#75 / #84). After the tier cascade has labeled clones at varying FDR thresholds, the typical follow-up is a shortlist that combines strict-FDR picks with phenotype-based rescues from the lower-tier pool:
Workflow¶
from tcrsift import (
aggregate_clonotypes,
build_clone_method_long,
compute_signature_scores_per_clonotype,
select_candidates,
compute_signature_picks_per_method,
)
# 1) Clonotype-level signature scores (mean log1p, CD8-restricted).
sig_scores = compute_signature_scores_per_clonotype(per_cell_df)
clones = aggregate_clonotypes(adata).merge(sig_scores, on="CDR3_pair")
# 2) Tag tier1 ∪ tier2 ∪ top-N-by-signature.
clones = select_candidates(clones, top_n=3)
shortlist = clones[clones["is_selected"]]
# 3) Optional per-method picks for the selection-route heatmap.
clone_method = build_clone_method_long(build_clone_sample_long(adata))
clone_method = clone_method.merge(sig_scores, on="CDR3_pair")
per_method_picks = compute_signature_picks_per_method(
clone_method, top_n=1, pool_clones=set(tier3_plus_clones),
)
API¶
candidate ¶
Signature-based candidate shortlisting (#75).
After the tier cascade has labeled clones at varying FDR thresholds, the typical follow-up is a shortlist:
Selected = tier1 ∪ tier2 ∪ top-N-per-signature(tier3 ∪ tier4 ∪ tier5)
For each named signature (antigen-response, cytolytic, tumor-reactive by default), take the top-N clones from the tier3+ pool by descending signature score. This pulls in clones that didn't make the strict-FDR cohort cut but have phenotype evidence we don't want to discard.
The function here is pure: it augments the input frame with boolean tracking columns describing how each clone made the shortlist, so a reviewer can audit why a clone is in the final list. Callers filter/export downstream.
select_candidates ¶
select_candidates(clonotypes: DataFrame, *, signatures: tuple[str, ...] = ('antigen_response', 'cytolytic', 'tumor_reactive'), top_n: int = 3, tier_col: str = 'tier', score_col_template: str = 'signature_{name}', tier1_label: str = 'tier1', tier2_label: str = 'tier2', tier3plus_labels: tuple[str, ...] = ('tier3', 'tier4', 'tier5')) -> pd.DataFrame
Augment clonotypes with shortlist tracking columns.
For each clone, computes:
tier1_or_tier2— bool. True iftier∈ {tier1, tier2}.tier3plus_top_by_{name}_signature— bool, one per signature. True if the clone is in the toptop_nclones of the tier3+ pool when ranked bysignature_{name}descending.is_selected— bool. The OR of all the above.
Does not filter the frame. The caller can export the
is_selected == True subset to candidate_shortlist.csv.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
clonotypes
|
DataFrame
|
Clonotypes frame from the standard tcrsift pipeline. Must
contain |
required |
signatures
|
tuple[str, ...]
|
Names of signatures to rank against. Each must have a column
named |
('antigen_response', 'cytolytic', 'tumor_reactive')
|
top_n
|
int
|
Picks per signature from the tier3+ pool. |
3
|
tier_col
|
str
|
Column holding the per-clone tier label. |
'tier'
|
score_col_template
|
str
|
|
'signature_{name}'
|
tier1_label
|
str
|
Tier labels in the frame. Defaults match
:data: |
'tier1'
|
tier2_label
|
str
|
Tier labels in the frame. Defaults match
:data: |
'tier1'
|
tier3plus_labels
|
str
|
Tier labels in the frame. Defaults match
:data: |
'tier1'
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Copy of |
Source code in tcrsift/candidate.py
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
compute_signature_picks_per_method ¶
compute_signature_picks_per_method(per_clone_method: DataFrame, *, signatures: tuple[str, ...] = ('antigen_response', 'cytolytic', 'tumor_reactive'), pool_clones: set | None = None, top_n: int = 1, min_cells: int = 2, method_col: str = 'method', clone_col: str = 'CDR3ab', cells_col: str = 'cells_in_method', score_col_template: str = 'signature_{name}') -> dict
Top-N tier3+ picks per (method, signature) by signature score (#84).
For each method, for each signature, rank clones in pool_clones
by their signature score (within that method's per-clone aggregate)
and take the top top_n clones with cells_in_method >= min_cells.
Used by the selection-route heatmap and the per-method candidate overlay. Pre-aggregating to (method, clone) BEFORE ranking is the correctness fix #84 calls out — ranking on the raw clone_sample_long can pick top_n rows from the same clone if the method has multiple samples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
per_clone_method
|
DataFrame
|
One row per (clone, method) with at least |
required |
signatures
|
tuple[str, ...]
|
Signature names to rank against. |
('antigen_response', 'cytolytic', 'tumor_reactive')
|
pool_clones
|
set | None
|
Restrict picks to this clone set (e.g. the tier3+ pool). When None, ranks all clones in the input. |
None
|
top_n
|
int
|
Picks per (method, signature); minimum cells in the method for a clone to be eligible. |
1
|
min_cells
|
int
|
Picks per (method, signature); minimum cells in the method for a clone to be eligible. |
1
|
method_col
|
str
|
Column names. |
'method'
|
clone_col
|
str
|
Column names. |
'method'
|
cells_col
|
str
|
Column names. |
'method'
|
score_col_template
|
str
|
Column names. |
'method'
|
Returns:
| Type | Description |
|---|---|
dict
|
|
Source code in tcrsift/candidate.py
signature_picks_clone_to_methods ¶
Invert :func:compute_signature_picks_per_method output (#84).
Input shape: {method: {signature: [clones]}}
Output shape: {clone: {signature: [methods]}}
Used to populate per-clone tier3_top_by_<sig>_signature_methods
columns on the candidate shortlist so a reviewer can see which
methods drove a clone's inclusion.