File size: 3,687 Bytes
a076a20
 
3bd086a
 
c614d3b
3bd086a
 
 
262d143
 
3bd086a
91f2cd2
3bd086a
 
 
 
 
 
 
 
 
 
 
 
 
 
dbaf3b6
 
 
91f2cd2
3bd086a
 
9de6162
3bd086a
6f04998
3bd086a
 
d46b5b7
252112f
91f2cd2
6f04998
 
 
 
 
91f2cd2
 
 
49627a9
 
252112f
49627a9
 
 
67900c2
49627a9
8e56998
262d143
d46b5b7
49627a9
d46b5b7
b84e820
3bd086a
 
262d143
6f04998
91f2cd2
49627a9
 
 
 
2271fb9
6f04998
7d45817
 
6f04998
262d143
 
1b64601
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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 = {}

    # ---------- helper function(s) ---------- 
    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)
            
    # ---------- public API ----------
    def compute_pai(self, participants_by_group=None):

        # input validation for 'participants_by_group'
        self.num_participants = sum(participants_by_group.values()) if participants_by_group else num_participants
        
        # absolute counts
        spi_a_abs = self.target_population - self.num_participants
        spi_b_abs = self.num_participants - self.feedback_volume

        # ----- 'Participation Dynamics' components -----
        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
        
        # ----- 'Reach and Equity' components -----
        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))

        # ----- percent-based values -----
        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 pivot value -----
        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": 
                {"Major Contributing Groups": f"At least {effective_groups_int} groups made major contributions.", 
                 "Equivalent Equal-Sized Groups": f"Overall participation feels roughly equivalent to {effective_groups_rounded} equally sized groups."
                }
        }

        return self.components_1, self.components_2