Update phase/compute.py
Browse filesmodified percent-based components
- phase/compute.py +11 -27
phase/compute.py
CHANGED
|
@@ -11,7 +11,7 @@ class ParticipationAdoptionIndex:
|
|
| 11 |
self.components_1 = {}
|
| 12 |
self.components_2 = {}
|
| 13 |
|
| 14 |
-
# ---------- helper
|
| 15 |
def _compute_pci(self, participants_by_group):
|
| 16 |
total = sum(participants_by_group.values())
|
| 17 |
if total == 0:
|
|
@@ -23,29 +23,10 @@ class ParticipationAdoptionIndex:
|
|
| 23 |
]
|
| 24 |
|
| 25 |
return sum(s ** 2 for s in shares)
|
| 26 |
-
|
| 27 |
-
def _normalize_components(self):
|
| 28 |
-
total = sum(abs(v["value"]) for v in self.components_1.values())
|
| 29 |
-
|
| 30 |
-
if total == 0:
|
| 31 |
-
for k in self.components_1:
|
| 32 |
-
if self.components_1[k]["value"] is not None:
|
| 33 |
-
self.components_1[k]["value"] = 0.0
|
| 34 |
-
else:
|
| 35 |
-
for k in self.components_1:
|
| 36 |
-
self.components_1[k]["value"] /= total
|
| 37 |
-
|
| 38 |
-
def _sort_components(self):
|
| 39 |
-
return dict(
|
| 40 |
-
sorted(
|
| 41 |
-
self.components_1.items(),
|
| 42 |
-
key=lambda item: abs(item[1]["value"]),
|
| 43 |
-
reverse=True
|
| 44 |
-
)
|
| 45 |
-
)
|
| 46 |
|
| 47 |
# ---------- public API ----------
|
| 48 |
def compute_pai(self, participants_by_group=None):
|
|
|
|
| 49 |
# absolute counts
|
| 50 |
spi_a_abs = self.target_population - self.num_participants
|
| 51 |
spi_b_abs = self.target_population - spi_a_abs - self.feedback_volume
|
|
@@ -55,23 +36,28 @@ class ParticipationAdoptionIndex:
|
|
| 55 |
spi_a = spi_a_abs / self.target_population
|
| 56 |
spi_b = spi_b_abs / self.target_population
|
| 57 |
peg = 1 - (self.feedback_volume / self.num_participants)
|
| 58 |
-
|
| 59 |
# ----- 'Reach and Equity' components -----
|
| 60 |
pci = self._compute_pci(participants_by_group) if participants_by_group else 0.0
|
| 61 |
effective_groups = 1.0 / pci if pci > 0 else 0.0
|
| 62 |
effective_groups_int = int(math.floor(effective_groups))
|
| 63 |
effective_groups_rounded = int(round(effective_groups))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
self.components_1 = {
|
| 66 |
-
"PCR (Participation Coverage Ratio)": {"Value":
|
| 67 |
"SPI-A (Silent Participation Inference - Silent Non-Adoption)": {"Value": spi_a, "Description": "High β Large segments of the target population were not reached or excluded. Low β Minimal non-participation across the target population."},
|
| 68 |
"SPI-B (Silent Participation Inference - Silent Adoption)": {"Value": spi_b, "Description": "High β Silent participation dominates. Low β Expressive participation dominates."},
|
| 69 |
-
"PEG (Participation-to-Expression Gap)": {"Value":
|
| 70 |
}
|
| 71 |
|
| 72 |
self.components_2 = {
|
| 73 |
"PCI (Participation Concentration Index)":
|
| 74 |
-
{"Value":
|
| 75 |
"Description": "β100 β Participation is concentrated to certain groups. β0 β Participation is balanced across groups."
|
| 76 |
},
|
| 77 |
"Group Summary":
|
|
@@ -80,6 +66,4 @@ class ParticipationAdoptionIndex:
|
|
| 80 |
}
|
| 81 |
}
|
| 82 |
|
| 83 |
-
# self._normalize_components()
|
| 84 |
-
|
| 85 |
return self.components_1, self.components_2
|
|
|
|
| 11 |
self.components_1 = {}
|
| 12 |
self.components_2 = {}
|
| 13 |
|
| 14 |
+
# ---------- helper function(s) ----------
|
| 15 |
def _compute_pci(self, participants_by_group):
|
| 16 |
total = sum(participants_by_group.values())
|
| 17 |
if total == 0:
|
|
|
|
| 23 |
]
|
| 24 |
|
| 25 |
return sum(s ** 2 for s in shares)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# ---------- public API ----------
|
| 28 |
def compute_pai(self, participants_by_group=None):
|
| 29 |
+
|
| 30 |
# absolute counts
|
| 31 |
spi_a_abs = self.target_population - self.num_participants
|
| 32 |
spi_b_abs = self.target_population - spi_a_abs - self.feedback_volume
|
|
|
|
| 36 |
spi_a = spi_a_abs / self.target_population
|
| 37 |
spi_b = spi_b_abs / self.target_population
|
| 38 |
peg = 1 - (self.feedback_volume / self.num_participants)
|
| 39 |
+
|
| 40 |
# ----- 'Reach and Equity' components -----
|
| 41 |
pci = self._compute_pci(participants_by_group) if participants_by_group else 0.0
|
| 42 |
effective_groups = 1.0 / pci if pci > 0 else 0.0
|
| 43 |
effective_groups_int = int(math.floor(effective_groups))
|
| 44 |
effective_groups_rounded = int(round(effective_groups))
|
| 45 |
+
|
| 46 |
+
# ----- percent-based values -----
|
| 47 |
+
final_pcr = round(pcr * 100, 2)
|
| 48 |
+
final_peg = round(peg * 100, 2)
|
| 49 |
+
final_pci = round(pci * 100, 2)
|
| 50 |
|
| 51 |
self.components_1 = {
|
| 52 |
+
"PCR (Participation Coverage Ratio)": {"Value": final_pcr, "Description": "β100 β Participation closely matches the target population. β0 β Participation reached very few of the intended population."},
|
| 53 |
"SPI-A (Silent Participation Inference - Silent Non-Adoption)": {"Value": spi_a, "Description": "High β Large segments of the target population were not reached or excluded. Low β Minimal non-participation across the target population."},
|
| 54 |
"SPI-B (Silent Participation Inference - Silent Adoption)": {"Value": spi_b, "Description": "High β Silent participation dominates. Low β Expressive participation dominates."},
|
| 55 |
+
"PEG (Participation-to-Expression Gap)": {"Value": final_peg, "Description": "β100 β High expression gap among participants. β0 β Minimal expression gap."}
|
| 56 |
}
|
| 57 |
|
| 58 |
self.components_2 = {
|
| 59 |
"PCI (Participation Concentration Index)":
|
| 60 |
+
{"Value": final_pci,
|
| 61 |
"Description": "β100 β Participation is concentrated to certain groups. β0 β Participation is balanced across groups."
|
| 62 |
},
|
| 63 |
"Group Summary":
|
|
|
|
| 66 |
}
|
| 67 |
}
|
| 68 |
|
|
|
|
|
|
|
| 69 |
return self.components_1, self.components_2
|