Examples
Every example on this page lives as a runnable, self-contained script under
examples/ in the repository, and is executed on every
push by tests/test_examples.py as part of
the CI workflow (see the badge on the project README).
This means the code and the output shown below are guaranteed to stay in sync with the current
version of the library -- if a change to ARMxtend breaks one of these examples, CI turns red.
Run any of them locally with:
pip install -e .
python examples/example_association_rules.py
Crisp association rules (ARM.association_rules + FFIM.fpgrowth)
Mines frequent itemsets with FP-Growth and then crisp association rules (support/confidence/lift), on the classic 10-transaction, 4-item dataset used throughout the FIM papers cited in Citing ARMxtend.
import pandas as pd
from ARMxtend.ARM.association_rules import association_rules
from ARMxtend.FFIM import fpgrowth
from ARMxtend.FIM._shared import key_to_itemset
TRANSACTIONS = [
"A,B,C", "B,D", "A,C,D", "B,C", "A,C",
"B,D", "A,B,C", "B,C,D", "A,B,D", "B,C,D",
]
def main():
transactions = [line.split(",") for line in TRANSACTIONS]
freqItemsets = fpgrowth(transactions, min_supp=0.3)
print("Itemsets frecuentes (min_supp=0.3):")
for itemsetKey, support in sorted(freqItemsets.items()):
print(" {:<10} support={:.2f}".format(itemsetKey, support))
itemsetsDf = pd.DataFrame({
"support": list(freqItemsets.values()),
"itemsets": [key_to_itemset(key) for key in freqItemsets],
})
rulesDf = association_rules(itemsetsDf, metric="confidence", min_threshold=0.7)
print("\nReglas de asociacion (min_confidence=0.7):")
for _, rule in rulesDf.iterrows():
antecedent = ",".join(sorted(rule["antecedents"]))
consequent = ",".join(sorted(rule["consequents"]))
print(" {} -> {:<6} support={:.2f} confidence={:.2f} lift={:.2f}".format(
antecedent, consequent, rule["support"], rule["confidence"], rule["lift"]))
return freqItemsets, rulesDf
if __name__ == "__main__":
main()
(full source: examples/example_association_rules.py)
Output:
Itemsets frecuentes (min_supp=0.3):
A support=0.50
A-B support=0.30
A-C support=0.40
B support=0.80
B-C support=0.50
B-D support=0.50
C support=0.70
C-D support=0.30
D support=0.60
Reglas de asociacion (min_confidence=0.7):
A -> C support=0.40 confidence=0.80 lift=1.14
D -> B support=0.50 confidence=0.83 lift=1.04
C -> B support=0.50 confidence=0.71 lift=0.89
Fuzzy association rules (FFIM.fuzzy_fpgrowth + FIM.FARE)
Reproduces, alpha-cut by alpha-cut, the worked example of Delgado, Ruiz, Sanchez & Serrano (2011)
-- see FIM.FARE -- for the rule {i1,i3} -> {i4}: FSupp = 0.266,
FConf = 0.5, FCF = 0.33. This is exactly what tests/test_examples.py
asserts, so any regression in the alpha-cut aggregation breaks CI immediately.
from ARMxtend.FFIM import fuzzy_fpgrowth
from ARMxtend.FIM.FARE import fuzzy_association_rules
# t1..t6, grados de pertenencia de i1..i5 (Tabla 2 del articulo)
FUZZY_TRANSACTIONS = [
[("i1", 1.0), ("i2", 0.2), ("i3", 1.0), ("i4", 0.8), ("i5", 0.9)],
[("i1", 1.0), ("i2", 1.0), ("i3", 0.8)],
[("i1", 0.4), ("i2", 0.1), ("i3", 0.7), ("i4", 0.6)],
[("i1", 0.6), ("i3", 0.4), ("i4", 0.4), ("i5", 0.5)],
[("i1", 0.4), ("i2", 0.1)],
[("i2", 1.0)],
]
NUM_ALPHA = 5 # alpha-cortes {1, 0.8, 0.6, 0.4, 0.2}, como en el articulo
def main():
freqItemsets = fuzzy_fpgrowth(FUZZY_TRANSACTIONS, min_supp=0.1, num_alpha=NUM_ALPHA)
rulesDf = fuzzy_association_rules(freqItemsets, NUM_ALPHA, metric="support", min_threshold=0.0)
target = next(
row for _, row in rulesDf.iterrows()
if set(row["antecedents"]) == {"i1", "i3"} and set(row["consequents"]) == {"i4"}
)
print("Comprobacion contra el articulo para {i1,i3} -> {i4}:")
print(" esperado FSupp=0.266 FConf=0.5 FCF=0.33")
print(" obtenido FSupp={:.3f} FConf={:.3f} FCF={:.3f}".format(
target["support"], target["confidence"], target["certainty_factor"]))
return freqItemsets, rulesDf
if __name__ == "__main__":
main()
(full source, including every printed itemset/rule: examples/example_fuzzy_association_rules.py)
Output (abridged -- the full run lists every fuzzy rule found):
Comprobacion contra el articulo para {i1,i3} -> {i4}:
esperado FSupp=0.266 FConf=0.5 FCF=0.33
obtenido FSupp=0.267 FConf=0.500 FCF=0.330
Meta-association rules (ARM.meta_rules)
Mines primary rules independently in three small datasets, then meta-rules describing which
primary rules co-occur across datasets -- crisp (presence/absence) and fuzzy (weighted by each
rule's own support/confidence). See ARM.meta_rules for the
underlying model (Ruiz et al., 2016).
from ARMxtend.ARM.meta_rules import (
mine_primary_rule_measures,
crisp_meta_association_rules,
fuzzy_meta_association_rules,
)
# Tres datasets D1, D2, D3 en los que A -> B es una regla fuerte y
# consistente (aparece siempre que aparece A), y C -> D solo aparece,
# debilmente, en D3.
DATASETS = [
[["A", "B"], ["A", "B"], ["A", "B"], ["C"]],
[["A", "B"], ["A", "B"], ["B"], ["C"]],
[["A", "B"], ["A", "B", "C", "D"], ["C", "D"], ["B"]],
]
def main():
ruleMeasuresPerDataset = mine_primary_rule_measures(DATASETS, min_supp=0.4, min_conf=0.5)
crispMetaRules = crisp_meta_association_rules(
ruleMeasuresPerDataset, min_supp=0.6, min_conf=0.6)
fuzzyMetaRules = fuzzy_meta_association_rules(
ruleMeasuresPerDataset, num_alpha=5, min_supp=0.3, min_conf=0.5)
return ruleMeasuresPerDataset, crispMetaRules, fuzzyMetaRules
if __name__ == "__main__":
main()
(full source, with the printing of every rule set: examples/example_meta_rules.py)
Output:
Reglas primarias minadas en cada dataset:
D1: {'A=>B': 1.0, 'B=>A': 1.0}
D2: {'A=>B': 1.0, 'B=>A': 0.6666666666666666}
D3: {'C=>D': 1.0, 'D=>C': 1.0, 'A=>B': 1.0, 'B=>A': 0.6666666666666666}
Meta-reglas crisp (co-ocurrencia de reglas entre datasets):
{'A=>B'} -> {'B=>A'} support=1.00 confidence=1.00
{'B=>A'} -> {'A=>B'} support=1.00 confidence=1.00
Meta-reglas difusas (ponderadas por la fuerza de cada regla primaria):
{'A=>B'} -> {'B=>A'} FSupp=0.73 FConf=0.73
{'B=>A'} -> {'A=>B'} FSupp=0.73 FConf=1.00
{'C=>D'} -> {'D=>C'} FSupp=0.33 FConf=1.00
{'D=>C'} -> {'C=>D'} FSupp=0.33 FConf=1.00
...
Note how the crisp variant only sees A=>B and B=>A co-occurring in all three datasets (a
boolean fact), while the fuzzy variant additionally distinguishes that the A=>B <-> B=>A
association (FSupp=0.73) is far more prominent than the C=>D <-> D=>C one (FSupp=0.33, since
C=>D/D=>C were only mined at all in dataset D3).
Preprocessing: fuzzifying a numeric attribute (preprocessing.FuzzyLib)
Turns a numeric temperature column into a Ruspini triangular fuzzy partition (cold /
comfortable / warm), the usual preprocessing step before feeding data into any of the fuzzy
mining algorithms above. See preprocessing.FuzzyLib.
import pandas as pd
from ARMxtend.preprocessing import FuzzyLib
def main():
fuzzyLib = FuzzyLib()
fuzzyLib.data = pd.DataFrame({
"temperature": [17.0, 19.5, 21.0, 23.0, 25.5, 28.0],
"sensor_id": ["s1", "s2", "s3", "s4", "s5", "s6"],
})
fuzzyLib.atributes = list(fuzzyLib.data.columns)
addedColumns = fuzzyLib.Fuzzification(
Atri=["temperature"],
thresholds=[[18, 21, 25]],
FuzzyLabel=[["cold", "comfortable", "warm"]],
)
print("Columnas difusas anadidas:", addedColumns)
print(fuzzyLib.GetData().to_string(index=False))
return fuzzyLib.GetData()
if __name__ == "__main__":
main()
(full source: examples/example_preprocessing.py)
Output:
Columnas difusas anadidas: ['temperature_cold', 'temperature_comfortable', 'temperature_warm']
temperature sensor_id temperature_cold temperature_comfortable temperature_warm
17.0 s1 1.0 0.0 0.0
19.5 s2 0.5 0.5 0.0
21.0 s3 0.0 1.0 0.0
23.0 s4 0.0 0.5 0.5
25.5 s5 0.0 0.0 1.0
28.0 s6 0.0 0.0 1.0
Visualization: the VizARE typed graph (VizARM.AREtoGraph)
Takes the crisp rules mined in the first example and transforms them into the VizARE typed
graph (item nodes + rule nodes, connected by antecedent/consequent edges) of Fernandez-Basso,
Ruiz, Molina-Solana & Martin-Bautista (2026), exports it to the paper's proposed intermediate
format (JSON Graph Format), and builds the optional rule-summarization layer (Section 4.2). See
VizARM.AREtoGraph.
import pandas as pd
from ARMxtend.ARM.association_rules import association_rules
from ARMxtend.FFIM import fpgrowth
from ARMxtend.FIM._shared import key_to_itemset
from ARMxtend.VizARM import AREtoGraph
TRANSACTIONS = [
"A,B,C", "B,D", "A,C,D", "B,C", "A,C",
"B,D", "A,B,C", "B,C,D", "A,B,D", "B,C,D",
]
def main():
transactions = [line.split(",") for line in TRANSACTIONS]
freqItemsets = fpgrowth(transactions, min_supp=0.3)
itemsetsDf = pd.DataFrame({
"support": list(freqItemsets.values()),
"itemsets": [key_to_itemset(key) for key in freqItemsets],
})
rulesDf = association_rules(itemsetsDf, metric="confidence", min_threshold=0.7)
graph = AREtoGraph.from_dataframe(rulesDf, rule_measures=("support", "confidence", "lift"))
# Each rule is its own node -- e.g. rule::A=>C -- linked to item nodes A
# (antecedent edge) and C (consequent edge); there is no direct A -> C edge.
print(graph.to_jgf())
summaryIds = graph.summarize(signature="consequent", measures=("confidence", "lift"))
return graph, summaryIds
if __name__ == "__main__":
main()
(full source: examples/example_vizarm.py)
Output (abridged):
Grafo: 4 nodos item, 3 nodos rule, 6 aristas
rule::A=>C: ['A'] -> ['C'] support=0.40 confidence=0.80 lift=1.14
rule::D=>B: ['D'] -> ['B'] support=0.50 confidence=0.83 lift=1.04
rule::C=>B: ['C'] -> ['B'] support=0.50 confidence=0.71 lift=0.89
JGF (formato intermedio propuesto, primeras lineas):
{
"graph": {
"directed": true,
"type": "association-rules",
"nodes": {
"rule::A=>C": {
"label": "A -> C",
"metadata": {
"kind": "rule",
"group": "rule",
"support": 0.4,
"confidence": 0.8,
Resumen por consecuente (2 grupos):
1 reglas -> ['C'] confidence en [0.80, 0.80] (media 0.80)
2 reglas -> ['B'] confidence en [0.71, 0.83] (media 0.77)
GraphML (Gephi/Cytoscape/NetworkX) and DOT (Graphviz) exports are still available as
graph.exportGraph(type=1)/type=2, for tools that don't consume JGF directly.
Big Data and streaming algorithms
The Spark-based algorithms (FIM.apriori, FIM.Eclat, FIM.BD_ARE, FIM.BD_FARE, SARE,
SFIM) are exercised in tests/test_fim_apriori_eclat.py, tests/test_sare_association_rules.py
and the rest of the tests/ suite against tests/spark_stub.py, a small local double of the Spark
RDD API -- see the User Guide for each algorithm's reference and the
pip install -e ".[spark]" note in the project README
for running them against a real cluster.