37  Beyond Lift: Advanced Metrics, Sensitivity, and Rule Structure

Author

Diego Villalba

Published

October 16, 2026

1 Introduction

The previous chapter established the foundations of association rule analysis: definitions of support, confidence, and lift, the rule generation process via the Apriori algorithm, and basic criteria for distinguishing genuine rules from trivial ones. The central argument was that generating rules is algorithmically simple, but critical evaluation of their validity demands moving beyond confidence as the sole criterion.

This chapter continues that line of reasoning and explores four directions that introductory treatments leave open. First, we rigorously analyze the structural limitations of lift as an evaluation metric: although lift corrects the bias of confidence, it possesses its own deficiencies that specialized literature has documented in detail, which are often ignored in introductory presentations. Second, we introduce a set of complementary metrics —leverage, conviction, and Zhang’s metric— whose mathematical properties allow evaluating aspects of rules that lift fails to capture, and whose combination yields more robust evaluations. Third, we address the issue of parameter sensitivity: we empirically demonstrate that the number, nature, and quality of rules obtained depend non-trivially on thresholds set by the analyst when invoking the algorithm, carrying direct methodological consequences. Finally, we propose representing the rule set as a relationship graph between items, enabling identification of the global structure of rule space and distinguishing core patterns from peripheral ones.

The common thread running through all these sections is identical to the one that motivated the previous chapter: the objective is not to maximize the number of reported rules, but to identify the small subset of rules representing nontrivial patterns, backed by consistent evidence from multiple perspectives.

2 Structural Limitations of Lift

2.1 The Symmetry of Lift and the Asymmetry of Decisions

An algebraic property of lift that few introductory presentations discuss in depth is its symmetry: for any pair of itemsets \(A\) and \(B\),

\[\text{lift}(A \Rightarrow B) = \frac{P(A \cup B)}{P(A) \cdot P(B)} = \frac{P(A \cup B)}{P(B) \cdot P(A)} = \text{lift}(B \Rightarrow A) \tag{1}\]

Symmetry follows directly from the commutativity of multiplication in the denominator. Lift measures the deviation of joint probability \(P(A \cup B)\) from expected value under independence \(P(A) \cdot P(B)\), and this deviation is identical regardless of which set is designated as antecedent or consequent.

This symmetry has a major practical consequence that frequently goes unnoticed. When the algorithm generates the two rules \(A \Rightarrow B\) and \(B \Rightarrow A\) from the same frequent itemset \(\{A, B\}\), both rules will have the exact same lift. However, their confidences will, in general, differ:

\[\text{conf}(A \Rightarrow B) = \frac{P(A \cup B)}{P(A)}, \qquad \text{conf}(B \Rightarrow A) = \frac{P(A \cup B)}{P(B)}\]

The rule with higher confidence is the one whose antecedent has lower individual support. If \(P(A) < P(B)\), then \(\text{conf}(A \Rightarrow B) > \text{conf}(B \Rightarrow A)\): predicting the more frequent item from the less frequent item is “easier” in terms of confidence, precisely because the consequent occurs with higher baseline frequency.

Table 37.1 illustrates this phenomenon with empirical data for the yogurt — whole milk pair:

Show code
par = reglas_base[
    (reglas_base["antecedents_str"].isin(["whole milk", "yogurt"])) &
    (reglas_base["consequents_str"].isin(["whole milk", "yogurt"])) &
    (reglas_base["antecedents"].apply(len) == 1)
][["regla", "antecedent support", "consequent support", "support",
   "confidence", "lift"]].round(3)
par
regla antecedent support consequent support support confidence lift
24 whole milk → yogurt 0.52 0.28 0.16 0.308 1.099
25 yogurt → whole milk 0.28 0.52 0.16 0.571 1.099
Table 1: The two directions of the yogurt — whole milk relationship share the same lift but different confidences. The direction {yogurt} → {whole milk} exhibits higher confidence because whole milk is the more frequent item of the pair.

The practical implication is direct: when the objective is taking an action conditioned on observing an item —“what should I recommend to someone buying \(X\)?”— rule direction matters, and lift alone cannot guide that choice. Confidence, despite its documented limitations, remains the relevant metric for directing that choice. A recommendation engine sorting rules purely by lift and picking the first direction encountered may be recommending the suboptimal direction.

2.2 Theoretical Ceiling of Lift and Cross-Rule Comparability

A second limitation of lift, equally critical and less widely known, is that its scale is not universal: the maximum achievable lift for a given pair depends on individual item frequencies. This property makes comparing lifts across rules with different individual support levels methodologically flawed in a strict sense.

To derive the theoretical ceiling, observe that co-occurrence support \(P(A \cup B)\) is bounded above by the support of the rarer item: if \(P(A) \leq P(B)\), then \(P(A \cup B) \leq P(A)\) (no more transactions can co-occur than those containing the rarer item). Therefore:

\[\text{lift}(A \Rightarrow B) = \frac{P(A \cup B)}{P(A) \cdot P(B)} \leq \frac{P(A)}{P(A) \cdot P(B)} = \frac{1}{P(B)} = \frac{1}{\max(P(A), P(B))} \tag{2}\]

The maximum theoretical lift for the pair \((A, B)\) is:

\[\text{lift}_{\max}(A, B) = \frac{1}{\max(P(A), P(B))} \tag{3}\]

This result has an immediate consequence: two frequent items —say, with support 0.50 each— have a maximum theoretical lift of just 2.0. Two rare items —with support 0.05 each— have a maximum theoretical lift of 20. An observed lift of 1.8 for the first pair represents 90% of its achievable maximum; the same lift of 1.8 for the second pair represents only 9%. The exact same figure signals a near-optimal rule in one case and a weak rule in the other.

To correct for this scale asymmetry, one can compute relative lift, defined as the fraction of theoretical maximum achieved by the observed lift:

\[\text{lift}_{\text{rel}}(A \Rightarrow B) = \frac{\text{lift}(A \Rightarrow B)}{\text{lift}_{\max}(A, B)} = \text{lift}(A \Rightarrow B) \cdot \max(P(A), P(B)) \tag{4}\]

Relative lift spans the range \((0, 1]\) and is directly comparable across rules with different frequency levels. A relative lift near 1 indicates that items co-occur with maximum possible frequency given their individual supports.

Show code
freq_rel = df.mean()

def lift_max_teorico(row):
    pa = freq_rel.get(row["antecedents_str"], np.nan)
    pb = freq_rel.get(row["consequents_str"], np.nan)
    if pd.isna(pa) or pd.isna(pb):
        return np.nan
    return 1.0 / max(pa, pb)

reglas_simples = reglas_base[
    reglas_base["antecedents"].apply(len) == 1
].copy()
reglas_simples["lift_max_teorico"] = reglas_simples.apply(lift_max_teorico, axis=1)
reglas_simples["lift_relativo"] = (
    reglas_simples["lift"] / reglas_simples["lift_max_teorico"]
).round(3)

reglas_simples[["regla", "lift", "lift_max_teorico", "lift_relativo"]].round(3).sort_values(
    "lift_relativo", ascending=False
).head(10)
regla lift lift_max_teorico lift_relativo
14 chips → soda 6.250 6.250 1.000
23 yogurt → granola 3.571 3.571 1.000
22 granola → yogurt 3.571 3.571 1.000
15 soda → chips 6.250 6.250 1.000
13 eggs → cheese 2.551 3.571 0.714
12 cheese → eggs 2.551 3.571 0.714
2 bread → coffee 1.562 2.500 0.625
3 coffee → bread 1.562 2.500 0.625
17 coffee → whole milk 1.202 1.923 0.625
16 whole milk → coffee 1.202 1.923 0.625
Table 2: Observed lift, theoretical maximum lift, and relative lift for rules with single-item antecedents. The lift and lift_max_teorico columns are not directly comparable across rows, whereas lift_relativo is.
Show code
fig = px.scatter(
    reglas_simples.dropna(subset=["lift_relativo"]),
    x="lift",
    y="lift_relativo",
    size="support",
    color="confidence",
    hover_data={
        "regla": True,
        "lift": ":.3f",
        "lift_max_teorico": ":.3f",
        "lift_relativo": ":.3f",
    },
    color_continuous_scale="Viridis",
    labels={
        "lift": "Observed Lift",
        "lift_relativo": "Relative Lift (fraction of theoretical max)",
        "confidence": "Confidence",
    },
    size_max=25,
)
fig.add_hline(
    y=0.5,
    line_dash="dot",
    line_color="darkorange",
    annotation_text="50% of theoretical max",
    annotation_position="bottom right",
)
fig.update_layout(height=460)
fig.show()
Figure 1: Observed lift (horizontal axis) versus relative lift —fraction of theoretical maximum— (vertical axis). Marker size indicates support; color indicates confidence. The orange dotted line marks 50% of maximum theoretical lift. Points in the bottom-right corner show high absolute lift but remain far from their maximum potential, indicating frequent items whose relationship is actually moderate.

Figure 37.1 reveals structure hidden by simply sorting by absolute lift. Rules in the upper-left quadrant —modest observed lift, but high relative lift— represent associations between infrequent items co-occurring at a significant fraction of their maximum possible theoretical ceiling: these are specific and solid rules, even if infrequent. Rules in the lower-right quadrant —higher absolute lift, but low relative lift— involve frequent items whose co-occurrence, while above chance, is far from as tight as absolute lift suggests.

3 Complementary Metrics to Lift

The catalog of proposed metrics for evaluating association rule interest is extensive: Tan et al. (2006) systematically enumerate and compare over twenty distinct measures. None is universally superior; each captures a distinct facet of what we intuitively call “interest.” This section details three metrics whose mathematical properties and complementarity with lift make them especially valuable in practice.

3.1 Leverage: Absolute Difference Above Chance

Leverage for a rule \(A \Rightarrow B\) measures the absolute difference between observed co-occurrence frequency and expected frequency under statistical independence:

\[\text{lev}(A \Rightarrow B) = P(A \cup B) - P(A) \cdot P(B) \tag{5}\]

This definition shares the exact structure of lift’s numerator, minus the normalization by \(P(A) \cdot P(B)\). Consequently, leverage preserves probability units, giving it an operationally direct interpretation: a leverage of 0.05 in a 1,000-transaction dataset means roughly 50 transactions contain both \(A\) and \(B\) beyond expectation under independence. This is the additional transaction count attributable to the association.

The theoretical range of leverage is \([-\min(P(A), P(B)) \cdot (1 - \max(P(A), P(B))),\; \min(P(A), P(B)) \cdot (1 - \max(P(A), P(B)))]\), centered at zero. Positive leverage indicates positive association; negative indicates inhibition; zero indicates independence —just like lift, but on an absolute rather than relative scale.

The key distinction between leverage and lift lies in scale. Lift normalizes deviation from independence into a dimensionless number comparable across rules with different consequents. Leverage gives the absolute magnitude of that deviation, which is more interpretable when quantifying rule impact: in recommendation engines, leverage is proportional to additional transactions generated by acting on the rule. However, this reliance on absolute frequencies makes leverage systematically low for rare items, even when their relative relationship is very strong —the exact inverse problem of absolute lift.

3.2 Conviction: Asymmetry and Quasi-Determinism

Conviction for a rule \(A \Rightarrow B\) was introduced to create a directional, asymmetric metric like confidence that simultaneously reflects departure from statistical independence (Tan et al. 2006):

\[\text{conv}(A \Rightarrow B) = \frac{1 - P(B)}{1 - \text{conf}(A \Rightarrow B)} = \frac{P(A) \cdot (1 - P(B))}{P(A) - P(A \cup B)} \tag{6}\]

Conviction’s interpretation is less intuitive than lift or leverage, but warrants careful examination. The numerator \(1 - P(B)\) is the expected frequency of rule “errors” —transactions where \(B\) does not occur— under independence: if \(A\) and \(B\) were independent, a fraction \(1 - P(B)\) of transactions containing \(A\) would lack \(B\). The denominator \(1 - \text{conf}(A \Rightarrow B)\) is the observed frequency of those errors. The ratio measures how many times fewer errors the rule makes compared to expectation under independence.

Several notable properties follow:

  • When \(A\) and \(B\) are independent, \(\text{conf}(A \Rightarrow B) = P(B)\), and conviction \(= (1 - P(B)) / (1 - P(B)) = 1\). Conviction equals 1 if and only if there is independence —just as lift equals 1 under independence.
  • As confidence approaches 1, the denominator approaches 0, and conviction approaches infinity. A rule with very high conviction is quasi-deterministic: observing \(A\) predicts \(B\) with near certainty.
  • When confidence is lower than \(P(B)\) (negative association), conviction is less than 1.
  • Unlike lift, conviction is asymmetric: \(\text{conv}(A \Rightarrow B) \neq \text{conv}(B \Rightarrow A)\) in general, making it well-suited for evaluating rule strength in its specific direction.

This asymmetry is particularly valuable when rule direction carries operational meaning: in recommendation systems, medical diagnostics, or any domain where acting on an antecedent predicts a consequent.

3.3 Zhang’s Metric: Bounded Range and Robustness

Proposed to address limitations of lift, Zhang’s metric is defined as (Tan et al. 2006):

\[Z(A, B) = \frac{P(A \cup B) - P(A) \cdot P(B)}{\max\left\{P(A \cup B)\cdot[1 - P(A)],\; P(A)\cdot[P(B) - P(A \cup B)]\right\}} \tag{7}\]

The numerator matches leverage: observed co-occurrence minus independence. The denominator normalizes the metric to ensure \(Z \in [-1, 1]\) for any item pair, regardless of individual frequencies. This property —lacking in lift— makes Zhang’s metric directly comparable across rules with varying frequency levels.

The denominator selects the maximum of two terms: \(P(A \cup B) \cdot [1 - P(A)]\), which dominates under high co-occurrence (strong positive association), and \(P(A) \cdot [P(B) - P(A \cup B)]\), which dominates under low co-occurrence (negative association or inhibition). This design guarantees a symmetric scale: \(Z = 1\) corresponds to maximum co-occurrence (\(A\) and \(B\) co-occur whenever the rarer item occurs), while \(Z = -1\) corresponds to minimum co-occurrence (mutual exclusion).

Zhang’s metric is symmetric —like lift— and exceptionally robust against highly frequent items, which cause the most severe bias in confidence and leverage. For these reasons, Tan et al. (2006) recommend Zhang’s metric as one of the most reliable measures for ranking rules by general interest when no prior domain knowledge is available.

3.4 Computation and Comparison of the Four Metrics

Show code
cols = ["regla", "support", "confidence", "lift",
        "leverage", "conviction", "zhang"]
reglas_base[cols].sort_values("zhang", ascending=False).head(8).round(3)
regla support confidence lift leverage conviction zhang
23 yogurt → granola 0.10 0.357 3.571 0.072 1.400 1.000
15 soda → chips 0.14 0.875 6.250 0.118 6.880 1.000
14 chips → soda 0.14 1.000 6.250 0.118 inf 0.977
13 eggs → cheese 0.10 0.357 2.551 0.061 1.338 0.844
22 granola → yogurt 0.10 1.000 3.571 0.072 inf 0.800
20 yogurt → fruit 0.12 0.429 2.143 0.064 1.400 0.741
12 cheese → eggs 0.10 0.714 2.551 0.061 2.520 0.707
21 fruit → yogurt 0.12 0.600 2.143 0.064 1.800 0.667
Table 3: The six evaluation metrics for the eight rules with highest Zhang value. Note how ranking by Zhang differs from ranking by lift: rules deemed most interesting by Zhang are not always those with highest absolute lift.

3.5 Correlation Between Metrics: Agreement and Discrepancy

Given multiple metrics, a natural question is whether they are redundant: if lift, leverage, and Zhang always rank rules identically, choice of metric is irrelevant. Correlation analysis provides an empirical answer.

Show code
metricas_cols = ["support", "confidence", "lift", "leverage", "conviction", "zhang"]
corr_matrix = reglas_base[metricas_cols].corr().round(2)

fig = px.imshow(
    corr_matrix,
    text_auto=True,
    color_continuous_scale="RdBu_r",
    zmin=-1,
    zmax=1,
    aspect="auto",
    labels={"color": "Correlation"},
)
fig.update_layout(height=430)
fig.show()
Figure 2: Pearson correlation matrix among the six evaluation metrics across the full rule set. Values are displayed inside each cell. Red-white-blue scale: deep red = high positive correlation, deep blue = high negative correlation, white = no correlation.

Figure 37.2 reveals several structural relationships. First, lift and Zhang show high positive correlation: both measure essential deviation from independence, differing in scale and extreme-value behavior. Second, leverage and support show moderate positive correlation: frequent items produce higher absolute leverage, reflecting leverage’s dependence on base frequencies. Third, conviction can exhibit low correlation with other metrics in certain datasets, precisely because it is sensitive to confidence values near 1 —where minor confidence shifts produce large conviction changes— while other metrics change smoothly.

Regions of low or negative correlation in this matrix are analytically most informative: where two metrics disagree, the analyst must decide which to weight higher based on context. A rule with high lift but low leverage involves infrequent items whose relative association is strong but whose absolute impact is limited. A rule with high Zhang but moderate conviction may be robust in overall association while not quasi-deterministic in direction.

3.6 The Multimetric Profile of a Rule

A method for visually summarizing a rule’s behavior across all metrics simultaneously is the normalized radar plot. For each rule, metrics are min-max scaled to \([0, 1]\) —for visualization purposes only, without assuming equal metric importance— and the resulting polygon is plotted.

Show code
metricas_viz = ["support", "confidence", "lift", "leverage", "zhang"]
scaler = MinMaxScaler()
reglas_norm = reglas_base.copy()
reglas_norm[metricas_viz] = scaler.fit_transform(reglas_base[metricas_viz])

top5_idx = reglas_base["lift"].nlargest(5).index
top5 = reglas_norm.loc[top5_idx]

fig = go.Figure()
for _, row in top5.iterrows():
    fig.add_trace(go.Scatterpolar(
        r=[row[m] for m in metricas_viz] + [row[metricas_viz[0]]],
        theta=metricas_viz + [metricas_viz[0]],
        fill="toself",
        name=row["regla"][:38],
        opacity=0.55,
    ))

fig.update_layout(
    polar=dict(radialaxis=dict(visible=True, range=[0, 1])),
    height=500,
    showlegend=True,
    legend=dict(x=1.05, y=1.0),
)
fig.show()
Figure 3: Normalized profile of top 5 rules by lift. Each axis corresponds to a metric min-max scaled to [0,1]. A larger, more regular polygon indicates a rule that is robust across multiple criteria simultaneously. Normalization is for display only and does not imply equal weighting.

Figure 37.3 compares five rules across five dimensions simultaneously. A rule with a large, regular polygon is robust: all metrics agree it is interesting. A rule with an asymmetric polygon —large on one axis, small on others— is strong under one criterion but weak under others, calling for cautious interpretation.

Table 37.4 summarizes qualitative interpretations of common profile patterns:

Profile Pattern Interpretation
Large, regular polygon Robust rule: consensus across multiple metrics
High lift, small leverage Strong relative association among rare items; limited absolute impact
Very high conviction, moderate rest Quasi-deterministic directional rule; confidence near 1
Small Zhang, moderate lift Lift may be inflated by base frequencies; Zhang corrects this
Small support, small everything Rare pattern, likely spurious; insufficient empirical evidence
Table 4: Interpretation of multimetric profiles.

4 Sensitivity to Algorithm Parameters

4.1 Thresholds as Decisions Lacking Intrinsic Statistical Basis

When invoking Apriori with specific parameters —e.g., min_support = 0.10 and minimum lift of 1.0— decisions are made that, unlike parameters in formal statistical models, carry no intrinsic statistical justification. No theory establishes that the “correct” minimum support is 0.10 rather than 0.08 or 0.12. Analysts select these thresholds based on practical considerations —compute time, manageable result set size, domain knowledge— but the algorithm accepts them blindly.

This circumstance carries serious methodological consequences: the resulting rule set is not an objective property of the dataset, but a joint function of the dataset and chosen parameters. Two analysts working on the same dataset with slightly different thresholds can arrive at substantially different rule sets, potentially reaching conflicting conclusions if unaware of this dependence. Sound methodology requires exploring result stability across reasonable parameter shifts —termed sensitivity analysis— and reporting those parameters alongside findings.

4.2 Sensitivity to Minimum Support

The first sensitivity experiment systematically varies \(\sigma_{\min}\) while fixing minimum lift at 1.0, tracking changes in rule counts and median rule quality.

Show code
soportes_grid = [0.06, 0.08, 0.10, 0.12, 0.14, 0.16, 0.18, 0.20]
resultados_sens = []

for s in soportes_grid:
    its = apriori(df, min_support=s, use_colnames=True)
    if len(its) == 0:
        resultados_sens.append({
            "σ_min": s, "Frequent itemsets": 0,
            "Rules": 0, "Median lift": np.nan, "Max lift": np.nan
        })
        continue
    r = association_rules(its, metric="lift", min_threshold=1.0)
    resultados_sens.append({
        "σ_min": round(s, 2),
        "Frequent itemsets": len(its),
        "Rules": len(r),
        "Median lift": round(r["lift"].median(), 3) if len(r) > 0 else np.nan,
        "Max lift": round(r["lift"].max(), 3) if len(r) > 0 else np.nan,
    })

pd.DataFrame(resultados_sens)
σ_min Frequent itemsets Rules Median lift Max lift
0 0.06 37 36 1.896 6.250
1 0.08 28 22 1.648 6.250
2 0.10 26 20 1.605 6.250
3 0.12 18 12 1.374 6.250
4 0.14 15 6 1.099 6.250
5 0.16 11 2 1.099 1.099
6 0.18 7 0 NaN NaN
7 0.20 6 0 NaN NaN
Table 5: Frequent itemset count, generated rule count, and rule set quality statistics as a function of minimum support. Minimum lift threshold fixed at 1.0.
Show code
df_sens = pd.DataFrame(resultados_sens)

fig = go.Figure()
fig.add_trace(go.Scatter(
    x=df_sens["σ_min"], y=df_sens["Rules"],
    mode="lines+markers", name="No. of rules",
    line=dict(color="#e63946", width=2.5), marker=dict(size=9),
    yaxis="y1",
))
fig.add_trace(go.Scatter(
    x=df_sens["σ_min"], y=df_sens["Median lift"],
    mode="lines+markers", name="Median lift",
    line=dict(color="#457b9d", width=2.5, dash="dash"), marker=dict(size=9),
    yaxis="y2",
))
fig.update_layout(
    xaxis=dict(title="Minimum support (σ_min)"),
    yaxis=dict(title="No. of generated rules", side="left", showgrid=True),
    yaxis2=dict(title="Median lift of rule set", overlaying="y", side="right", showgrid=False),
    legend=dict(x=0.60, y=0.92),
    height=430,
)
fig.show()
Figure 4: Behavior of rule count (left axis, red) and median set lift (right axis, dashed blue) vs. minimum support. The two curves move in opposite directions: higher support yields fewer rules but higher median quality.

The behavior in Figure 37.4 is neither accidental nor dataset-specific: it is a structural property of rule mining. Raising \(\sigma_{\min}\) excludes less frequent itemsets. Many of these involve rare items co-occurring by chance in the sample —precisely the patterns most vulnerable to statistical instability. Filtering them leaves a remaining rule set with higher average support and higher median lift. Informally: patterns surviving stricter filters are, on average, more robust.

The tension between these curves reflects the fundamental trade-off in association rule mining: one cannot simultaneously maximize rule quantity and average quality. Every support threshold represents a choice within this trade-off space, governed by the relative cost of two error types: including spurious rules (false positives) versus omitting genuine but rare patterns (false negatives).

4.3 Sensitivity to Lift Threshold

The second experiment fixes support at 0.10 and varies minimum lift across a wide range. The result yields a rule set survival curve: for each threshold, how many rules survive.

Show code
its_fijo = apriori(df, min_support=0.10, use_colnames=True)
lifts_umbral = np.round(np.arange(0.5, 2.6, 0.1), 1)
curva_supervivencia = []

for lt in lifts_umbral:
    r = association_rules(its_fijo, metric="lift", min_threshold=float(lt))
    curva_supervivencia.append({
        "Minimum lift threshold": lt,
        "Surviving rules": len(r),
    })

df_surv = pd.DataFrame(curva_supervivencia)

fig = px.line(
    df_surv,
    x="Minimum lift threshold",
    y="Surviving rules",
    markers=True,
    color_discrete_sequence=["#2a9d8f"],
)
fig.add_vline(
    x=1.0, line_dash="dash", line_color="crimson",
    annotation_text="lift = 1 (independence)",
    annotation_position="top right",
    annotation_font_color="crimson",
)
fig.update_layout(height=390)
fig.show()
Figure 5: Rule set survival curve vs. minimum lift threshold. Each point answers: if lift ≥ x is required, how many rules remain? A steep drop at value x indicates many rules cluster just above that threshold.

Curve shape in Figure 37.5 reveals lift distribution characteristics. A steep drop in \([1.0, 1.3]\) indicates many rules exhibit lift barely above independence —formally nontrivial but marginally interesting. A gradual drop suggests lifts are more evenly distributed over a wide range. In both cases, the curve identifies the lift threshold where the rule set stabilizes at a manageable size without discarding top patterns.

4.4 Full Map of Parameter Space

The comprehensive sensitivity analysis explores both key parameters simultaneously: minimum support and minimum confidence. The result is a 2D surface depicting rule counts generated for each parameter combination.

Show code
grid_support = np.round(np.arange(0.06, 0.22, 0.02), 2)
grid_conf    = np.round(np.arange(0.20, 1.00, 0.10), 2)
heatmap_data = []

for s in grid_support:
    for c in grid_conf:
        its = apriori(df, min_support=float(s), use_colnames=True)
        if len(its) == 0:
            heatmap_data.append({"min_support": s, "min_confidence": c, "n_reglas": 0})
            continue
        r = association_rules(its, metric="confidence", min_threshold=float(c))
        heatmap_data.append({
            "min_support": s,
            "min_confidence": c,
            "n_reglas": len(r),
        })

df_hm = pd.DataFrame(heatmap_data)
pivot = df_hm.pivot(index="min_confidence", columns="min_support", values="n_reglas")

fig = px.imshow(
    pivot,
    color_continuous_scale="YlOrRd",
    labels={"x": "Minimum support", "y": "Minimum confidence", "color": "No. of rules"},
    aspect="auto",
    text_auto=True,
)
fig.update_layout(height=450)
fig.show()
Figure 6: Heatmap of rule counts vs. minimum support (horizontal axis) and minimum confidence (vertical axis). Bottom-left region —loose thresholds— yields maximum rules with lowest average quality. Top-right region —strict thresholds— yields few or no rules, but high reliability. Analysts must deliberately navigate this trade-off.

Figure 37.6 summarizes the analyst’s decision space. Each cell answers: selecting these thresholds yields how many rules? High-density regions (bottom-left, deep red) represent loose thresholds yielding high rule counts —along with high numbers of spurious rules. Low-density regions (top-right, pale yellow/white) represent strict thresholds yielding few rules, each backed by high frequency and strong predictive power.

The critical methodological lesson is: no single point on this map is correct in the abstract. Threshold choices are always relative to problem context. In retail with millions of daily transactions, min_support = 0.01 is justified because 1% represents thousands of observations. In a medical dataset with 200 patients, that same threshold equals just 2 cases —statistically inadequate for any claim. Correct selection requires translating support percentages into absolute observation counts and judging whether that sample size supports the intended claim.

5 Global Structure of Rule Space: Graph Representation

5.1 Motivation for a Network Representation

Previous sections represented rules as tables and metric scatter plots. Both forms help evaluate individual rules or small subsets, but obscure the relational structure connecting items globally. An item can participate in many rules as antecedent or consequent; two items may connect directly via a rule or indirectly through an intermediate item. This topological structure is invisible in tabular form.

Graph representations make this structure explicit. Formally, we construct a graph \(G = (V, E)\) where vertex set \(V\) comprises unique items participating in at least one filtered rule, and edge set \(E\) contains directed edge \((A, B)\) for every rule \(A \Rightarrow B\) exceeding minimum lift and support thresholds. To maintain readability, we restrict focus to single-item antecedents and consequents (1-itemsets).

5.2 Centrality, Hubs, and Bridge Nodes

In graph theory, node centrality measures relative importance in the network. Among multiple definitions, a natural metric in association rules is the sum of lifts for all rules involving the item as antecedent or consequent. This weights items participating in many strong associations, rather than merely many associations.

Show code
reglas_grafo = reglas_base[
    (reglas_base["lift"] > 1.1) &
    (reglas_base["support"] >= 0.10) &
    (reglas_base["antecedents"].apply(len) == 1) &
    (reglas_base["consequents"].apply(len) == 1)
].copy()

nodos = list(set(
    reglas_grafo["antecedents_str"].tolist() +
    reglas_grafo["consequents_str"].tolist()
))
n_nodos = len(nodos)
nodo_idx = {nd: i for i, nd in enumerate(nodos)}

angulos = [2 * math.pi * i / n_nodos for i in range(n_nodos)]
xs = [math.cos(a) for a in angulos]
ys = [math.sin(a) for a in angulos]

# Centrality by sum of lifts
centralidad = {}
for nd in nodos:
    r_sub = reglas_grafo[
        (reglas_grafo["antecedents_str"] == nd) |
        (reglas_grafo["consequents_str"] == nd)
    ]
    centralidad[nd] = r_sub["lift"].sum()

edge_x, edge_y = [], []
for _, row in reglas_grafo.iterrows():
    x0 = xs[nodo_idx[row["antecedents_str"]]]
    y0 = ys[nodo_idx[row["antecedents_str"]]]
    x1 = xs[nodo_idx[row["consequents_str"]]]
    y1 = ys[nodo_idx[row["consequents_str"]]]
    edge_x += [x0, x1, None]
    edge_y += [y0, y1, None]

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=edge_x, y=edge_y,
    mode="lines",
    line=dict(width=1.2, color="#cccccc"),
    hoverinfo="none",
    showlegend=False,
))

fig.add_trace(go.Scatter(
    x=xs, y=ys,
    mode="markers+text",
    text=nodos,
    textposition="top center",
    textfont=dict(size=10),
    marker=dict(
        size=[max(12, centralidad.get(nd, 1) * 5) for nd in nodos],
        color=[centralidad.get(nd, 0) for nd in nodos],
        colorscale="Plasma",
        showscale=True,
        colorbar=dict(title="Centrality<br>(Σ lifts)"),
        line=dict(color="white", width=1),
    ),
    hovertext=[
        f"<b>{nd}</b><br>Centrality: {centralidad.get(nd, 0):.2f}<br>"
        f"Connected rules: {len(reglas_grafo[(reglas_grafo['antecedents_str']==nd)|(reglas_grafo['consequents_str']==nd)])}"
        for nd in nodos
    ],
    hoverinfo="text",
    showlegend=False,
))

fig.update_layout(
    xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
    yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
    height=540,
    plot_bgcolor="white",
    margin=dict(t=30, b=30, l=30, r=30),
)
fig.show()
Figure 7: Association rule graph for single items with lift > 1.1 and support ≥ 0.10. Each node is an item; each edge is a rule meeting thresholds. Node size and color depict centrality (sum of lifts for connected rules). Large, bright nodes represent items involved in multiple strong associations; small, dark nodes are peripheral.

Figure 37.7 visualizes rule space topology. Highly central nodes participate in multiple strong associations, not simply high edge counts. An item can become a hub for two distinct reasons: being genuinely central to market basket co-purchases —its co-occurrences far exceed expectations from individual frequencies— or being so ubiquitous that it co-occurs with nearly everything, albeit with low lift.

Distinguishing genuine centrality from frequency-driven spurious centrality parallels the confidence issue: just as high confidence can artifactually arise from consequent base frequency, high network centrality can stem from sheer item ubiquity. Weighting centrality by lift —rather than raw co-occurrence counts— serves to correct this bias.

Equally important is the bridge node or broker: an item with few network neighbors connecting item clusters that would otherwise remain disconnected. In basket analysis, a bridge node might represent a niche item acting as a trigger for a specific purchasing chain. Such nodes are invisible in frequency-only analyses but offer high marketing actionability.

5.3 The “Whole Milk Problem”: A Case Study

Analyzing whole milk in Groceries concretely illustrates these challenges. Present in ~58% of sample transactions, whole milk is a dominant item whose high frequency systematically distorts metrics for every rule targeting it as consequent.

Show code
p_wm = df["whole milk"].mean()
print(f"Whole milk support: {p_wm:.3f}")
print(f"Appears in {int(p_wm * len(df))} of {len(df)} transactions\n")

wm_consecuente = reglas_base[
    reglas_base["consequents_str"] == "whole milk"
][["regla", "support", "confidence", "lift", "zhang"]].sort_values("lift", ascending=False)

print("All rules with whole milk as consequent:")
print(wm_consecuente.round(3).to_string(index=False))
Whole milk support: 0.520
Appears in 26 of 50 transactions

All rules with whole milk as consequent:
              regla  support  confidence  lift  zhang
coffee → whole milk     0.10       0.625 1.202  0.200
yogurt → whole milk     0.16       0.571 1.099  0.125
butter → whole milk     0.14       0.538 1.036  0.046
 bread → whole milk     0.16       0.400 0.769 -0.333
  eggs → whole milk     0.10       0.357 0.687 -0.388
Show code
print(f"P(whole milk) = {p_wm:.3f}\n")
print(f"For lift > 1.0:  conf > {p_wm:.3f}")
print(f"For lift > 1.2:  conf > {1.2 * p_wm:.3f}")
print(f"For lift > 1.5:  conf > {1.5 * p_wm:.3f}")
print(f"For lift > 2.0:  conf > {2.0 * p_wm:.3f}\n")

candidatas = reglas_base[
    (reglas_base["consequents_str"] == "whole milk") &
    (reglas_base["lift"] > 1.2)
]
if len(candidatas) > 0:
    print("Rules with whole milk as consequent and lift > 1.2:")
    print(candidatas[["regla", "confidence", "lift"]].round(3).to_string(index=False))
else:
    print("No rules targeting whole milk exceed lift > 1.2.")
    print("Conclusion: whole milk is not a useful consequent in this dataset.")
P(whole milk) = 0.520

For lift > 1.0:  conf > 0.520
For lift > 1.2:  conf > 0.624
For lift > 1.5:  conf > 0.780
For lift > 2.0:  conf > 1.040

Rules with whole milk as consequent and lift > 1.2:
              regla  confidence  lift
coffee → whole milk       0.625 1.202

The analysis confirms theoretical predictions: when \(P(B)\) is very high, the headroom for a rule \(A \Rightarrow B\) to be genuinely nontrivial shrinks dramatically. Achieving lift > 1.5 requires \(\text{conf}(A \Rightarrow B) > 1.5 \times 0.58 \approx 0.87\): nearly 9 out of 10 transactions containing \(A\) must also include whole milk. This condition is nearly impossible in general retail where milk is ubiquitous. The takeaway is not dataset defectiveness, but that whole milk makes a poor consequent in association rule mining: its ubiquity prevents rules predicting it from yielding actionable insight.

Generalizing, for any item \(B\), the confidence threshold required for a rule to be nontrivial by factor \(k\) is:

\[\text{conf}(A \Rightarrow B) > k \cdot P(B) \qquad \text{equivalently,} \qquad \text{lift}(A \Rightarrow B) > k \tag{8}\]

This relationship enables systematically building consequent-specific threshold tables for analysts to consult prior to interpreting rules.

Show code
umbrales = []
for item in sorted(df.columns):
    p = df[item].mean()
    umbrales.append({
        "Item (consequent)": item,
        "P(item)": round(p, 3),
        "min conf (lift > 1.0)": round(p, 3),
        "min conf (lift > 1.5)": round(min(1.0, 1.5 * p), 3),
    })

pd.DataFrame(umbrales).sort_values("P(item)", ascending=False)
Item (consequent) P(item) min conf (lift > 1.0) min conf (lift > 1.5)
13 whole milk 0.52 0.52 0.78
1 bread 0.40 0.40 0.60
7 eggs 0.28 0.28 0.42
14 yogurt 0.28 0.28 0.42
2 butter 0.26 0.26 0.39
8 fruit 0.20 0.20 0.30
12 vegetables 0.18 0.18 0.27
6 coffee 0.16 0.16 0.24
10 soda 0.16 0.16 0.24
4 cheese 0.14 0.14 0.21
5 chips 0.14 0.14 0.21
9 granola 0.10 0.10 0.15
11 sugar 0.10 0.10 0.15
0 beer 0.04 0.04 0.06
3 candy 0.04 0.04 0.06
Table 6: Minimum confidence thresholds required for a rule to be nontrivial (lift > 1.0) or moderately interesting (lift > 1.5), computed for each item as a potential consequent. Items with high P(item) require very high confidence to yield genuinely informative rules.

6 An Integrated Evaluation Framework

6.1 From Fragmentation to Coherence

The concepts developed across this chapter —lift limitations, complementary metrics, parameter sensitivity, graph structure— are not isolated components. They form a unified framework answering a core question: how much confidence does a specific rule warrant?

Answering this question involves multiple dimensions:

  1. Relative Dimension: How far does observed lift deviate from independence relative to theoretical maximum given item supports? Relative lift addresses this.

  2. Absolute Dimension: How many additional transactions beyond baseline independence exhibit co-occurrence? Leverage answers this.

  3. Directional Predictive Dimension: How deterministic is the rule in its specific direction? Conviction addresses this.

  4. Normalized Robustness Dimension: Is the association strong on a scale comparable across varying item frequencies? Zhang’s metric resolves this.

  5. Parametric Stability Dimension: Does the rule persist across reasonable threshold choices, or vanish under slight \(\sigma_{\min}\) tightening? Sensitivity analysis addresses this.

A rule showing strength across all dimensions earns high confidence. A rule succeeding in only one or two calls for caution. The following function systematically executes this multidimensional evaluation:

Show code
def evaluar_regla_completa(row, n_transacciones=50, verbose=True):
    """
    Multidimensional evaluation of an association rule.
    Returns qualitative classification: ROBUST / CANDIDATE / DISCARD
    """
    criterios = []
    puntos = 0

    # Dimension 1: Lift
    if row["lift"] > 1.5:
        criterios.append("Strong lift (> 1.5)")
        puntos += 3
    elif row["lift"] > 1.1:
        criterios.append("Moderate lift (1.1 – 1.5)")
        puntos += 1
    else:
        criterios.append("Weak lift (≤ 1.1) — indistinguishable from chance")

    # Dimension 2: Absolute support
    n_obs = int(row["support"] * n_transacciones)
    if n_obs >= 10:
        criterios.append(f"Solid support ({n_obs} of {n_transacciones} transactions)")
        puntos += 2
    elif n_obs >= 5:
        criterios.append(f"Minimum support ({n_obs} of {n_transacciones} transactions)")
        puntos += 1
    else:
        criterios.append(f"Insufficient support ({n_obs} of {n_transacciones} transactions)")

    # Dimension 3: Zhang (normalized robustness)
    if row["zhang"] > 0.3:
        criterios.append("Robust Zhang (> 0.3)")
        puntos += 2
    elif row["zhang"] > 0.1:
        criterios.append("Moderate Zhang (0.1 – 0.3)")
        puntos += 1
    else:
        criterios.append("Weak Zhang (≤ 0.1) — likely base frequency artifact")

    # Dimension 4: Conviction (directional determinism)
    if row["conviction"] > 1.5:
        criterios.append("High conviction (> 1.5) — quasi-deterministic rule")
        puntos += 1

    clasificacion = (
        "ROBUST"    if puntos >= 6 else
        "CANDIDATE"  if puntos >= 3 else
        "DISCARD"
    )

    if verbose:
        print(f"{'─'*55}")
        print(f"Rule:  {row['regla']}")
        print(f"{'─'*55}")
        for c in criterios:
            print(f"  • {c}")
        print(f"\n  → Classification: {clasificacion}  ({puntos}/8 points)\n")

    return clasificacion

# Evaluate top 6 rules by lift
print("Evaluation of top 6 rules by lift:\n")
for _, row in reglas_base.sort_values("lift", ascending=False).head(6).iterrows():
    evaluar_regla_completa(row)
Evaluation of top 6 rules by lift:

───────────────────────────────────────────────────────
Rule:  soda → chips
───────────────────────────────────────────────────────
  • Strong lift (> 1.5)
  • Minimum support (7 of 50 transactions)
  • Robust Zhang (> 0.3)
  • High conviction (> 1.5) — quasi-deterministic rule

  → Classification: ROBUST  (7/8 points)

───────────────────────────────────────────────────────
Rule:  chips → soda
───────────────────────────────────────────────────────
  • Strong lift (> 1.5)
  • Minimum support (7 of 50 transactions)
  • Robust Zhang (> 0.3)
  • High conviction (> 1.5) — quasi-deterministic rule

  → Classification: ROBUST  (7/8 points)

───────────────────────────────────────────────────────
Rule:  yogurt → granola
───────────────────────────────────────────────────────
  • Strong lift (> 1.5)
  • Minimum support (5 of 50 transactions)
  • Robust Zhang (> 0.3)

  → Classification: ROBUST  (6/8 points)

───────────────────────────────────────────────────────
Rule:  granola → yogurt
───────────────────────────────────────────────────────
  • Strong lift (> 1.5)
  • Minimum support (5 of 50 transactions)
  • Robust Zhang (> 0.3)
  • High conviction (> 1.5) — quasi-deterministic rule

  → Classification: ROBUST  (7/8 points)

───────────────────────────────────────────────────────
Rule:  eggs → cheese
───────────────────────────────────────────────────────
  • Strong lift (> 1.5)
  • Minimum support (5 of 50 transactions)
  • Robust Zhang (> 0.3)

  → Classification: ROBUST  (6/8 points)

───────────────────────────────────────────────────────
Rule:  cheese → eggs
───────────────────────────────────────────────────────
  • Strong lift (> 1.5)
  • Minimum support (5 of 50 transactions)
  • Robust Zhang (> 0.3)
  • High conviction (> 1.5) — quasi-deterministic rule

  → Classification: ROBUST  (7/8 points)

6.2 What Changes with This Framework

The difference between basic association rule analysis in introductory texts and the critical framework developed here lies not in code: mlxtend functions remain identical. The difference lies in the questions asked before interpreting results and the conceptual tools applied.

Table 44.2 summarizes this distinction:

Dimension Basic Approach Critical Approach
Metrics considered Support, confidence Lift, relative lift, leverage, conviction, Zhang
Rule direction Ignored Evaluated via confidence asymmetry
Lift comparability Assumed universal Corrected with relative lift
Parameter thresholds Fixed by convention Explored via sensitivity analysis
Visualization Sorted tables Metric scatter + radar + graph
Final selection criterion Single confidence or lift Convergence across multiple metrics
Table 7: Comparison between basic and critical approaches to association rule mining.

This comparison highlights that critical analysis is not merely extra labor —it is structurally distinct in its epistemic framework. Analysts employing the critical framework typically report smaller rule sets than those relying on basic approaches. However, those smaller sets are backed by far more robust evidence, resist parameter fluctuations, and yield superior practical actionability.

7 Conceptual Summary

This chapter explored association rule mining beyond fundamental metrics. Key takeaways:

On Structural Limitations of Lift:

  • Lift is symmetric: \(\text{lift}(A \Rightarrow B) = \text{lift}(B \Rightarrow A)\). Selecting rule direction for practical applications relies on confidence —an asymmetric metric.
  • Lift has a theoretical ceiling dependent on individual supports: \(\text{lift}_{\max} = 1 / \max(P(A), P(B))\). Comparing raw lifts across rules with differing supports can be misleading. Relative lift —ratio of observed to maximum lift— provides a fairer basis for comparison.

On Complementary Metrics:

  • Leverage measures absolute difference between observed co-occurrence and independence. It reflects additional transactions attributable to association, but is systematically low for rare items.
  • Conviction is asymmetric and measures rule quasi-determinism in direction: very high values signal confidence near 1.
  • Zhang’s metric spans \([-1, 1]\), is symmetric, and resists frequent-item bias. It is recommended for comparing rules across varying frequency regimes.
  • Metrics are non-redundant: imperfect correlations mean metric discrepancies offer key analytical signals.

On Parameter Sensitivity:

  • Apriori thresholds carry no intrinsic statistical justification. Resulting rule sets are a joint function of dataset and chosen parameters.
  • Sensitivity analysis —systematic exploration of parameter space— is a mandatory methodological practice.
  • The support-confidence map visualizes full decision space, letting analysts deliberately position choices along the quantity vs. quality curve.

On Graph Representations:

  • Rule graphs reveal network topology: hubs, bridge nodes, and item clusters.
  • Lift-weighted centrality —rather than raw edge counts— distinguishes genuinely central items from frequency-driven artifacts.
  • The “Whole Milk Problem” demonstrates how high consequent frequency makes discovering informative rules nearly impossible regardless of thresholds.

On the Integrated Framework:

  • Robust rule evaluation requires examining at least four dimensions simultaneously: relative lift, leverage, Zhang, and conviction.
  • Robust rules show convergence across multiple metrics; candidate rules show partial convergence; discarded rules fail under stricter metrics.

References