def apriori(dataset, minsupport, maxsize):
    from collections import defaultdict

    baskets = defaultdict(list)
    pointers = defaultdict(list)

    for i, ds in enumerate(dataset):
        for ell in ds:
            pointers[ell].append(i)
            baskets[frozenset([ell])].append(i)

    # Convert pointer items to frozensets to speed up operations later
    new_pointers = dict()
    for k in pointers:
        if len(pointers[k]) >= minsupport:
            new_pointers[k] = frozenset(pointers[k])
    pointers = new_pointers
    for k in baskets:
        baskets[k] = frozenset(baskets[k])


    # Valid are all elements whose support is >= minsupport
    valid = set()
    for el, c in baskets.items():
        if len(c) >= minsupport:
            valid.update(el)

    # Itemsets at first iteration are simply all singleton with valid elements:
    itemsets = [frozenset([v]) for v in valid]
    freqsets = []
    for i in range(maxsize - 1):
        print("At iteration {}, number of frequent baskets: {}".format(
            i, len(itemsets)))
        newsets = []
        for it in itemsets:
            ccounts = baskets[it]

            for v, pv in pointers.items():
                if v not in it:
                    csup = (ccounts & pv)
                    if len(csup) >= minsupport:
                        new = frozenset(it | frozenset([v]))
                        if new not in baskets:
                            newsets.append(new)
                            baskets[new] = csup
        freqsets.extend(itemsets)
        itemsets = newsets
        if not len(itemsets):
            break
    support = {}
    for k in baskets:
        support[k] = float(len(baskets[k]))
    return freqsets, support


# A namedtuple to collect all values that may be interesting
freqsets, support = apriori(dataset, minsupport, maxsize)
dataset/ETHPy150Open luispedro/BuildingMachineLearningSystemsWithPython/ch08/apriori/apriori.py/apriori