From 03758079f09c10f0d881daf26b9c80082b66149a Mon Sep 17 00:00:00 2001 From: Damien Z Wang <752879139h@gmail.com> Date: Wed, 1 Apr 2026 19:50:55 +0100 Subject: [PATCH 1/3] fix (calculateCriterion): add epsilon to avoid nan. --- src/pyWitness/DataProcessed.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pyWitness/DataProcessed.py b/src/pyWitness/DataProcessed.py index 2649690..2b1c04d 100644 --- a/src/pyWitness/DataProcessed.py +++ b/src/pyWitness/DataProcessed.py @@ -489,13 +489,22 @@ def p0(x, a,b) : return dPrime def calculateCriterion(self): - zT = _special.ndtri(self.data_rates.loc['targetPresent','suspectId']) - try : - zL = _special.ndtri(self.data_rates.loc['targetAbsent','suspectId']) - except : # only for TA showups and the participant never made a suspectId - zL = _special.ndtri(self.data_rates.loc['targetAbsent','rejectId']) + # Add epsilon correction to prevent infinite z-scores + epsilon = 0.5 / len(self.dataRaw.data) # Laplace correction + hit_rate = self.data_rates.loc['targetPresent', 'suspectId'].values + fa_rate = self.data_rates.loc['targetAbsent', 'suspectId'].values + + # Clip rates to avoid 0.0 and 1.0 + hit_rate = _np.clip(hit_rate, epsilon, 1 - epsilon) + fa_rate = _np.clip(fa_rate, epsilon, 1 - epsilon) + + zT = _special.ndtri(hit_rate) + try: + zL = _special.ndtri(fa_rate) + except: # only for TA showups and the participant never made a suspectId + zL = _special.ndtri(self.data_rates.loc['targetAbsent', 'rejectId']) - dCriterion = - (zT + zL)/2.0 + dCriterion = - (zT + zL) / 2.0 dCriterion.name = ("criterion", "central") self.data_rates = _pandas.concat([self.data_rates, _pandas.DataFrame(dCriterion).transpose()]) self.data_rates = self.data_rates.sort_index() From 03b3c5b84cdf4c9d1634b408e736679075270698 Mon Sep 17 00:00:00 2001 From: Damien Z Wang <752879139h@gmail.com> Date: Wed, 1 Apr 2026 20:23:12 +0100 Subject: [PATCH 2/3] fix (calculateCriterion): fixed. --- src/pyWitness/DataProcessed.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pyWitness/DataProcessed.py b/src/pyWitness/DataProcessed.py index 2b1c04d..ca842c4 100644 --- a/src/pyWitness/DataProcessed.py +++ b/src/pyWitness/DataProcessed.py @@ -491,8 +491,8 @@ def p0(x, a,b) : def calculateCriterion(self): # Add epsilon correction to prevent infinite z-scores epsilon = 0.5 / len(self.dataRaw.data) # Laplace correction - hit_rate = self.data_rates.loc['targetPresent', 'suspectId'].values - fa_rate = self.data_rates.loc['targetAbsent', 'suspectId'].values + hit_rate = self.data_rates.loc['targetPresent','suspectId'].values + fa_rate = self.data_rates.loc['targetAbsent','suspectId'].values # Clip rates to avoid 0.0 and 1.0 hit_rate = _np.clip(hit_rate, epsilon, 1 - epsilon) @@ -501,11 +501,12 @@ def calculateCriterion(self): zT = _special.ndtri(hit_rate) try: zL = _special.ndtri(fa_rate) - except: # only for TA showups and the participant never made a suspectId - zL = _special.ndtri(self.data_rates.loc['targetAbsent', 'rejectId']) + except : # only for TA showups and the participant never made a suspectId + zL = _special.ndtri(self.data_rates.loc['targetAbsent','rejectId']) - dCriterion = - (zT + zL) / 2.0 - dCriterion.name = ("criterion", "central") + dCriterion = - (zT + zL)/2.0 + template = self.data_rates.loc['dprime', 'central'] # Use existing row as template + dCriterion = _pandas.Series(dCriterion, name=("criterion", "central"), index=template.index) self.data_rates = _pandas.concat([self.data_rates, _pandas.DataFrame(dCriterion).transpose()]) self.data_rates = self.data_rates.sort_index() From b4ceef128e19ac3e138fd09da7d04e5ad956818a Mon Sep 17 00:00:00 2001 From: Damien Z Wang <752879139h@gmail.com> Date: Thu, 2 Apr 2026 12:03:06 +0100 Subject: [PATCH 3/3] fix (calculateCriterion): Keep it clean. --- src/pyWitness/DataProcessed.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/pyWitness/DataProcessed.py b/src/pyWitness/DataProcessed.py index ca842c4..ab47de6 100644 --- a/src/pyWitness/DataProcessed.py +++ b/src/pyWitness/DataProcessed.py @@ -489,24 +489,21 @@ def p0(x, a,b) : return dPrime def calculateCriterion(self): - # Add epsilon correction to prevent infinite z-scores - epsilon = 0.5 / len(self.dataRaw.data) # Laplace correction - hit_rate = self.data_rates.loc['targetPresent','suspectId'].values - fa_rate = self.data_rates.loc['targetAbsent','suspectId'].values + epsilon = 0.5 / len(self.dataRaw.data) + hit_rate = self.data_rates.loc['targetPresent','suspectId'].copy() - # Clip rates to avoid 0.0 and 1.0 - hit_rate = _np.clip(hit_rate, epsilon, 1 - epsilon) - fa_rate = _np.clip(fa_rate, epsilon, 1 - epsilon) + try : + fa_rate = self.data_rates.loc['targetAbsent','suspectId'].copy() + except KeyError: + fa_rate = self.data_rates.loc['targetAbsent','rejectId'].copy() + hit_rate = hit_rate.clip(lower=epsilon, upper=1 - epsilon) + fa_rate = fa_rate.clip(lower=epsilon, upper=1 - epsilon) zT = _special.ndtri(hit_rate) - try: - zL = _special.ndtri(fa_rate) - except : # only for TA showups and the participant never made a suspectId - zL = _special.ndtri(self.data_rates.loc['targetAbsent','rejectId']) + zL = _special.ndtri(fa_rate) dCriterion = - (zT + zL)/2.0 - template = self.data_rates.loc['dprime', 'central'] # Use existing row as template - dCriterion = _pandas.Series(dCriterion, name=("criterion", "central"), index=template.index) + dCriterion.name = ("criterion", "central") self.data_rates = _pandas.concat([self.data_rates, _pandas.DataFrame(dCriterion).transpose()]) self.data_rates = self.data_rates.sort_index()