PRACTICAL 10: ASSOCIATION - APRIORI (GROCERIES DATASET)

STEPS:
1. Install the libraries:  pip install pandas seaborn matplotlib mlxtend
2. Load groceries.csv and remove the empty (nan / None) items from every transaction.
3. Convert the transactions into a one-hot table using TransactionEncoder.
4. Find the frequent itemsets with Apriori (min_support = 0.01).
5. Plot the top 15 itemsets by support.
6. Generate the association rules with lift >= 1.
7. Filter the rules (antecedent length >= 2 with confidence > 0.3, and consequent length >= 2).
8. Print the rules by the metrics lift, confidence, leverage and conviction.

CODE:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, association_rules
data = pd.read_csv("groceries.csv")
print("First 5 rows of raw data:\n", data.head())
transactions = data.values.astype(str).tolist()
transactions = [[item for item in row if item != 'nan' and item != 'None'] for row in transactions]
print("\nFirst 2 cleaned transactions:\n", transactions[:2])
te = TransactionEncoder()
te_ary = te.fit(transactions).transform(transactions)
df = pd.DataFrame(te_ary, columns=te.columns_)
print("\nOne-hot encoded shape:", df.shape)
frequent_itemset = apriori(df, min_support=0.01, use_colnames=True)
print(f"Total frequent itemsets found: {len(frequent_itemset)}")
top_15 = frequent_itemset.nlargest(n=15, columns='support').copy()
top_15['itemset_str'] = top_15['itemsets'].apply(lambda x: ', '.join(list(x)))
plt.figure(figsize=(12, 6))
colors = ['#FFB6C1', '#ADD8E6', '#98FB98', '#FFD700', '#FFA07A', '#87CEEB', '#FFC0CB', '#FF69B4', '#00FA9A', '#FF6347']
sns.barplot(x='itemset_str', y='support', data=top_15, hue='itemset_str', palette=colors[:len(top_15)], legend=False)
plt.xticks(rotation=45, ha='right')
plt.title("Top Frequent Itemsets by Support")
plt.tight_layout()
plt.show()
rules = association_rules(frequent_itemset, metric="lift", min_threshold=1)
rules = rules.sort_values(by=['support'], ascending=False)
rules["antecedent_len"] = rules["antecedents"].apply(lambda x: len(x))
rules["consequent_len"] = rules["consequents"].apply(lambda x: len(x))
rule_3_filtered = rules[(rules['antecedent_len'] >= 2) &
                        (rules['confidence'] > 0.3) &
                        (rules['lift'] > 1)].sort_values(by=['lift', 'support'], ascending=False)
print("\nRule 3 (Antecedent Len >= 2, Conf > 0.3, Lift > 1):\n", rule_3_filtered.head())
rule_4_filtered = rules[(rules['consequent_len'] >= 2) &
                        (rules['lift'] > 1)].sort_values(by=['lift', 'confidence'], ascending=False)
print("\nRule 4 (Consequent Len >= 2, Lift > 1):\n", rule_4_filtered.head())
print("---------------------ACCURACY METRICS-------------------------------")
rules = association_rules(frequent_itemset, metric="lift", min_threshold=1)
print(rules)
rules = association_rules(frequent_itemset,metric="confidence",min_threshold=1)
print(rules)
rules = association_rules(frequent_itemset,metric="leverage",min_threshold=1)
print(rules)
rules = association_rules(frequent_itemset,metric="conviction",min_threshold=1)
print(rules)

EXPLANATION:
- Apriori finds the items that are bought together often, using the support (how frequent an itemset is).
- TransactionEncoder turns every basket into True / False columns, one per item, which Apriori needs.
- association_rules() makes rules like "A -> B" and measures them with support, confidence and lift (lift > 1 means the items really go together).
- The filters keep the stronger multi-item rules (antecedent >= 2 items with confidence > 0.3, and consequent >= 2 items).
- The last part prints the rules by lift, confidence, leverage and conviction to compare the metrics.
