Files

43 lines
2.6 KiB
Python

"""Orthogonal evidence axes. Never converts predicted dopamine to DAN identity."""
import numpy as np
import pandas as pd
def roles(meta, mapped_dan_ids=()):
required=['neuron_idx','body_id','annotation_class','annotation_type','neurotransmitter','nt_ground_truth']
missing=set(required)-set(meta.columns)
if missing:raise ValueError(f'Missing actual schema columns: {sorted(missing)}')
out=meta[required].copy()
cls=meta.annotation_class.fillna('');typ=meta.annotation_type.fillna('')
nt=meta.neurotransmitter.fillna('').str.strip().str.lower()
out['metadata_dopamine']=nt.eq('dopamine')
out['annotation_DAN']=cls.eq('DAN')
out['annotation_DPM']=typ.eq('DPM')
out['has_frozen_MB_DAN_mapping']=meta.neuron_idx.isin(mapped_dan_ids)
out['has_raw_ground_truth']=meta.nt_ground_truth.notna() & meta.nt_ground_truth.fillna('').ne('')
out['identity_conflict']=out.annotation_DAN & out.annotation_DPM
out['role_group']='other_annotation'
out.loc[cls.isin(['ALPN','olfactory']),'role_group']='PN_olfactory_annotation'
out.loc[cls.eq('Kenyon_Cell'),'role_group']='KC_annotation'
out.loc[cls.eq('MBON'),'role_group']='MBON_annotation'
out.loc[typ.eq('APL'),'role_group']='APL_annotation'
other_dop=out.metadata_dopamine & ~out.annotation_DAN & ~out.annotation_DPM
# Preserve separate evidence booleans even when the reporting group is disjoint.
out.loc[other_dop & out.role_group.eq('other_annotation'),'role_group']='dopamine_metadata_role_unknown'
out.loc[out.annotation_DAN,'role_group']='DAN_annotation'
out.loc[out.annotation_DPM,'role_group']='DPM_annotation'
out.loc[out.identity_conflict,'role_group']='identity_conflict_unknown'
return out
def self_test():
x=pd.DataFrame({'neuron_idx':np.arange(5,dtype=np.int32),'body_id':np.arange(5,dtype=np.uint64),
'annotation_class':[None,'DAN',None,'DAN',None],'annotation_type':['DPM','PAM15',None,'DPM','PAM-not-proof'],
'neurotransmitter':['dopamine']*5,'nt_ground_truth':[None]*5})
y=roles(x,[1])
assert y.annotation_DAN.tolist()==[False,True,False,True,False]
assert y.role_group.tolist()==['DPM_annotation','DAN_annotation','dopamine_metadata_role_unknown','identity_conflict_unknown','dopamine_metadata_role_unknown']
assert not y.has_raw_ground_truth.any() and y.has_frozen_MB_DAN_mapping.tolist()==[False,True,False,False,False]
try:roles(x.drop(columns='nt_ground_truth'))
except ValueError:pass
else:raise AssertionError('Missing schema must fail')
return {'pass':True,'DPM_not_inferred_DAN':True,'PAM_name_not_identity_proof':True,'unknown_retained':True,'conflict_flagged':True,'schema_fail_closed':True}