|
|
import math |
|
|
|
|
|
class ParticipationAdoptionIndex: |
|
|
|
|
|
def __init__(self, num_participants, target_population, feedback_volume): |
|
|
self.num_participants = num_participants |
|
|
self.target_population = target_population |
|
|
self.feedback_volume = feedback_volume |
|
|
self.components_1 = {} |
|
|
self.components_2 = {} |
|
|
|
|
|
|
|
|
def _compute_pci(self, participants_by_group): |
|
|
total = sum(participants_by_group.values()) |
|
|
if total == 0: |
|
|
return 0.0 |
|
|
|
|
|
shares = [ |
|
|
count / total |
|
|
for count in participants_by_group.values() |
|
|
] |
|
|
|
|
|
return sum(s ** 2 for s in shares) |
|
|
|
|
|
|
|
|
def compute_pai(self, participants_by_group=None): |
|
|
|
|
|
|
|
|
self.num_participants = sum(participants_by_group.values()) if participants_by_group else num_participants |
|
|
|
|
|
|
|
|
spi_a_abs = self.target_population - self.num_participants |
|
|
spi_b_abs = self.num_participants - self.feedback_volume |
|
|
|
|
|
|
|
|
pcr = self.num_participants / self.target_population |
|
|
spi_a = spi_a_abs / self.target_population |
|
|
spi_b = spi_b_abs / self.num_participants |
|
|
peg = spi_b_abs / self.target_population |
|
|
|
|
|
|
|
|
pci = self._compute_pci(participants_by_group) if participants_by_group else 0.0 |
|
|
effective_groups = 1.0 / pci if pci > 0 else 0.0 |
|
|
effective_groups_int = int(math.floor(effective_groups)) |
|
|
effective_groups_rounded = int(round(effective_groups)) |
|
|
|
|
|
|
|
|
final_pcr = round(pcr * 100, 2) |
|
|
final_spi_a = round(spi_a * 100, 2) |
|
|
final_spi_b = round(spi_b * 100, 2) |
|
|
final_peg = round((pcr - peg) / pcr * 100 if pcr > 0 else 0.0, 2) |
|
|
final_pci = round(pci, 2) |
|
|
|
|
|
|
|
|
pci_mid = 0.5 |
|
|
|
|
|
|
|
|
self.components_1 = { |
|
|
"PCR (Participation Coverage Ratio)": {"Value": final_pcr, "Description": f"{final_pcr}% of the target population have participated."}, |
|
|
"SPI-A (Silent Participation Inference - Silent Non-Adoption)": {"Value": final_spi_a, "Description": f"{final_spi_a}% of the target population were not reached or excluded."}, |
|
|
"SPI-B (Silent Participation Inference - Silent Adoption)": {"Value": final_spi_b, "Description": f"{final_spi_b}% of the participants have participated silently."}, |
|
|
"PEG (Participation-to-Expression Gap)": {"Value": final_peg, "Description": f"There is a {final_peg}% gap between participation and expressed feedback."} |
|
|
} |
|
|
|
|
|
self.components_2 = { |
|
|
"PCI (Participation Concentration Index)": |
|
|
{"Value": final_pci, |
|
|
"Description": ( |
|
|
f"A PCI of {final_pci} suggests " |
|
|
f"{'high' if final_pci >= pci_mid else 'low'} participation concentration, " |
|
|
f"{'dominated by fewer groups' if final_pci >= pci_mid else 'with participation spread across groups'}." |
|
|
)}, |
|
|
"Group Summary": |
|
|
{"Minimum Participating Groups": f"At least {effective_groups_int} groups meaningfully participated.", |
|
|
"Effective Participation Groups": f"Participation is roughly equivalent to {effective_groups_rounded} equally sized groups." |
|
|
} |
|
|
} |
|
|
|
|
|
return self.components_1, self.components_2 |