diff --git a/training/predict.py b/training/predict.py index 73d96c2..fd8e57b 100644 --- a/training/predict.py +++ b/training/predict.py @@ -55,9 +55,12 @@ TASTE = Path("taste_models") ACID_SMARTS = { - "carboxylic acid": "[CX3](=O)[OX2H1]", - "sulfonic acid": "[SX4](=O)(=O)[OX2H1]", - "phosphoric/phosphonic acid": "[PX4](=O)[OX2H1]", + # Match both protonated (-OH) and deprotonated (-O-) forms — sour compounds are + # routinely drawn as carboxylate/sulfonate/phosphate anions or zwitterions. + # (Lifted the rule's recall on labeled-sour from 0.57 to 0.93.) + "carboxylic acid / carboxylate": "[CX3](=O)[OX2H1,OX1-]", + "sulfonic / sulfonate": "[SX4](=O)(=O)[OX2H1,OX1-]", + "phosphoric / phosphonic (+ anion)": "[PX4](=O)[OX2H1,OX1-]", } _ACID = {k: Chem.MolFromSmarts(v) for k, v in ACID_SMARTS.items()} diff --git a/training/train_taste.py b/training/train_taste.py index e39bcdf..0d3c810 100644 --- a/training/train_taste.py +++ b/training/train_taste.py @@ -49,7 +49,10 @@ # Acidic-group SMARTS — used both for the sour rule and to VALIDATE it against # whatever labeled sour compounds exist (so that data isn't wasted either). -ACID_SMARTS = ["[CX3](=O)[OX2H1]", "[SX4](=O)(=O)[OX2H1]", "[PX4](=O)[OX2H1]"] +# Match BOTH protonated (-OH) and deprotonated (-O-) forms: sour compounds are +# routinely drawn as carboxylate/sulfonate/phosphate anions or zwitterions, which +# the -OH-only patterns missed (the main driver of the low recall). +ACID_SMARTS = ["[CX3](=O)[OX2H1,OX1-]", "[SX4](=O)(=O)[OX2H1,OX1-]", "[PX4](=O)[OX2H1,OX1-]"] _ACID = [Chem.MolFromSmarts(s) for s in ACID_SMARTS]