thenukegun10x commited on
Commit
ee2f67f
·
verified ·
1 Parent(s): 37960d3

Update src\data\taxonomy.py

Browse files
Files changed (1) hide show
  1. src/data/taxonomy.py +162 -0
src/data/taxonomy.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Taxonomic Hierarchy Engine for Western Australia Flora.
3
+ Builds and maps Species -> Genus -> Family for hierarchical multi-task classification.
4
+ """
5
+ import pandas as pd
6
+ from pathlib import Path
7
+
8
+ # Common WA Flora Genus -> Family mapping dictionary
9
+ GENUS_TO_FAMILY = {
10
+ # Proteaceae
11
+ "Banksia": "Proteaceae", "Grevillea": "Proteaceae", "Hakea": "Proteaceae",
12
+ "Dryandra": "Proteaceae", "Adenanthos": "Proteaceae", "Isopogon": "Proteaceae",
13
+ "Petrophile": "Proteaceae", "Synaphea": "Proteaceae", "Conospermum": "Proteaceae",
14
+ "Lambertia": "Proteaceae", "Persoonia": "Proteaceae", "Xylomelum": "Proteaceae",
15
+ "Franklandia": "Proteaceae", "Stirlingia": "Proteaceae",
16
+
17
+ # Myrtaceae
18
+ "Eucalyptus": "Myrtaceae", "Corymbia": "Myrtaceae", "Melaleuca": "Myrtaceae",
19
+ "Verticordia": "Myrtaceae", "Calothamnus": "Myrtaceae", "Darwinia": "Myrtaceae",
20
+ "Chamelaucium": "Myrtaceae", "Thryptomene": "Myrtaceae", "Beaufortia": "Myrtaceae",
21
+ "Baeckea": "Myrtaceae", "Regelia": "Myrtaceae", "Calytrix": "Myrtaceae",
22
+ "Eremaea": "Myrtaceae", "Kunzea": "Myrtaceae", "Micromyrtus": "Myrtaceae",
23
+ "Hypocalymma": "Myrtaceae", "Scholtzia": "Myrtaceae", "Phymatocarpus": "Myrtaceae",
24
+ "Leptospermum": "Myrtaceae", "Astartea": "Myrtaceae", "Taxandria": "Myrtaceae",
25
+
26
+ # Fabaceae (Legumes)
27
+ "Acacia": "Fabaceae", "Gastrolobium": "Fabaceae", "Daviesia": "Fabaceae",
28
+ "Jacksonia": "Fabaceae", "Bossiaea": "Fabaceae", "Hovea": "Fabaceae",
29
+ "Kennedia": "Fabaceae", "Hardenbergia": "Fabaceae", "Gompholobium": "Fabaceae",
30
+ "Mirbelia": "Fabaceae", "Chorizema": "Fabaceae", "Pultenaea": "Fabaceae",
31
+ "Isotropis": "Fabaceae", "Swainsona": "Fabaceae", "Senna": "Fabaceae",
32
+ "Indigofera": "Fabaceae", "Templetonia": "Fabaceae", "Latrobea": "Fabaceae",
33
+
34
+ # Orchidaceae (Orchids)
35
+ "Caladenia": "Orchidaceae", "Thelymitra": "Orchidaceae", "Diuris": "Orchidaceae",
36
+ "Pterostylis": "Orchidaceae", "Drakaea": "Orchidaceae", "Microtis": "Orchidaceae",
37
+ "Prasophyllum": "Orchidaceae", "Cyanicula": "Orchidaceae", "Ericksonella": "Orchidaceae",
38
+ "Leporella": "Orchidaceae", "Paracaleana": "Orchidaceae", "Pyrorchis": "Orchidaceae",
39
+ "Cryptostylis": "Orchidaceae", "Elythranthera": "Orchidaceae", "Spiculaea": "Orchidaceae",
40
+
41
+ # Haemodoraceae (Kangaroo Paws)
42
+ "Anigozanthos": "Haemodoraceae", "Macropidia": "Haemodoraceae", "Conostylis": "Haemodoraceae",
43
+ "Tribonanthes": "Haemodoraceae", "Haemodorum": "Haemodoraceae", "Phlebocarya": "Haemodoraceae",
44
+
45
+ # Ericaceae / Epacridaceae (Heaths)
46
+ "Leucopogon": "Ericaceae", "Astroloma": "Ericaceae", "Lysinema": "Ericaceae",
47
+ "Conostephium": "Ericaceae", "Andersonia": "Ericaceae", "Sphenotoma": "Ericaceae",
48
+ "Styphelia": "Ericaceae", "Cosmelia": "Ericaceae",
49
+
50
+ # Goodeniaceae
51
+ "Goodenia": "Goodeniaceae", "Dampiera": "Goodeniaceae", "Scaevola": "Goodeniaceae",
52
+ "Lechenaultia": "Goodeniaceae", "Velleia": "Goodeniaceae", "Anthotium": "Goodeniaceae",
53
+
54
+ # Stylidiaceae (Triggerplants)
55
+ "Stylidium": "Stylidiaceae", "Levenhookia": "Stylidiaceae",
56
+
57
+ # Droseraceae (Sundews / Carnivorous)
58
+ "Drosera": "Droseraceae",
59
+
60
+ # Asteraceae (Daisies)
61
+ "Rhodanthe": "Asteraceae", "Waitzia": "Asteraceae", "Schoenia": "Asteraceae",
62
+ "Podolepis": "Asteraceae", "Olearia": "Asteraceae", "Senecio": "Asteraceae",
63
+ "Brachyscome": "Asteraceae", "Lawrencella": "Asteraceae", "Xerochrysum": "Asteraceae",
64
+
65
+ # Xanthorrhoeaceae / Asphodelaceae
66
+ "Xanthorrhoea": "Asphodelaceae",
67
+
68
+ # Dasypogonaceae
69
+ "Kingia": "Dasypogonaceae", "Dasypogon": "Dasypogonaceae", "Calectasia": "Dasypogonaceae",
70
+
71
+ # Casuarinaceae (Sheoaks)
72
+ "Allocasuarina": "Casuarinaceae", "Casuarina": "Casuarinaceae",
73
+
74
+ # Pittosporaceae
75
+ "Marianthus": "Pittosporaceae", "Billardiera": "Pittosporaceae", "Pittosporum": "Pittosporaceae",
76
+ "Cheiranthera": "Pittosporaceae",
77
+
78
+ # Restionaceae (Rushes / Sedges)
79
+ "Desmocladus": "Restionaceae", "Alexgeorgea": "Restionaceae", "Loxocarya": "Restionaceae",
80
+ "Chordifex": "Restionaceae", "Lyginia": "Restionaceae",
81
+
82
+ # Chenopodiaceae / Amaranthaceae
83
+ "Atriplex": "Amaranthaceae", "Maireana": "Amaranthaceae", "Tecticornia": "Amaranthaceae",
84
+ "Ptilotus": "Amaranthaceae",
85
+
86
+ # Malvaceae
87
+ "Alyogyne": "Malvaceae", "Thomasia": "Malvaceae", "Guichenotia": "Malvaceae",
88
+ "Lasiopetalum": "Malvaceae", "Seringia": "Malvaceae", "Androcalva": "Malvaceae",
89
+
90
+ # Rutaceae (Boronias / Waxflowers)
91
+ "Boronia": "Rutaceae", "Philotheca": "Rutaceae", "Diplolaena": "Rutaceae",
92
+ "Correa": "Rutaceae", "Crowea": "Rutaceae", "Geleznowia": "Rutaceae",
93
+ "Asterolasia": "Rutaceae", "Eriostemon": "Rutaceae",
94
+
95
+ # Loranthaceae (Mistletoes / Christmas Tree)
96
+ "Nuytsia": "Loranthaceae", "Amyema": "Loranthaceae", "Lysiana": "Loranthaceae",
97
+ }
98
+
99
+ class TaxonomyHierarchy:
100
+ """Manages species -> genus -> family indices and mappings."""
101
+ def __init__(self, species_list: list[str]):
102
+ self.species_list = sorted(list(set(s for s in species_list if isinstance(s, str) and s.strip())))
103
+
104
+ # 1. Species Index
105
+ self.species_to_idx = {s: i for i, s in enumerate(self.species_list)}
106
+ self.idx_to_species = {i: s for s, i in self.species_to_idx.items()}
107
+ self.n_species = len(self.species_list)
108
+
109
+ # 2. Genus Index
110
+ self.species_to_genus = {}
111
+ genera_set = set()
112
+ for s in self.species_list:
113
+ genus = s.split()[0] if s else "Unknown"
114
+ self.species_to_genus[s] = genus
115
+ genera_set.add(genus)
116
+
117
+ self.genus_list = sorted(list(genera_set))
118
+ self.genus_to_idx = {g: i for i, g in enumerate(self.genus_list)}
119
+ self.idx_to_genus = {i: g for g, i in self.genus_to_idx.items()}
120
+ self.n_genera = len(self.genus_list)
121
+
122
+ # 3. Family Index
123
+ # FIX: avoid synthetic per-genus families (previous f"{g}_Family" exploded to ~250 singletons).
124
+ # Unknown genera now collapsed to a single "Unknown_Family" bucket to keep loss meaningful.
125
+ self.genus_to_family = {}
126
+ families_set = set()
127
+ unknown_genera: list[str] = []
128
+ for g in self.genus_list:
129
+ fam = GENUS_TO_FAMILY.get(g)
130
+ if fam is None:
131
+ fam = "Unknown_Family"
132
+ unknown_genera.append(g)
133
+ self.genus_to_family[g] = fam
134
+ families_set.add(fam)
135
+ if unknown_genera:
136
+ print(
137
+ f"[taxonomy] {len(unknown_genera)}/{len(self.genus_list)} genera fallback to Unknown_Family "
138
+ f"(e.g. {unknown_genera[:5]})",
139
+ flush=True,
140
+ )
141
+
142
+ self.family_list = sorted(list(families_set))
143
+ self.family_to_idx = {f: i for i, f in enumerate(self.family_list)}
144
+ self.idx_to_family = {i: f for f, i in self.family_to_idx.items()}
145
+ self.n_families = len(self.family_list)
146
+
147
+ # Precompute lookup tables
148
+ self.species_idx_to_genus_idx = [
149
+ self.genus_to_idx[self.species_to_genus[self.idx_to_species[i]]]
150
+ for i in range(self.n_species)
151
+ ]
152
+ self.species_idx_to_family_idx = [
153
+ self.family_to_idx[self.genus_to_family[self.species_to_genus[self.idx_to_species[i]]]]
154
+ for i in range(self.n_species)
155
+ ]
156
+
157
+ def get_taxonomy_indices(self, species_name: str) -> tuple[int, int, int]:
158
+ """Returns (species_idx, genus_idx, family_idx)."""
159
+ s_idx = self.species_to_idx.get(species_name, -1)
160
+ if s_idx == -1:
161
+ return -1, -1, -1
162
+ return s_idx, self.species_idx_to_genus_idx[s_idx], self.species_idx_to_family_idx[s_idx]