forked from jacksonpradolima/gsp-py
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgsp.py
More file actions
139 lines (110 loc) · 4.58 KB
/
Copy pathgsp.py
File metadata and controls
139 lines (110 loc) · 4.58 KB
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
===============================================
GSP (Generalized Sequential Pattern) algorithm
===============================================
GSP algorithm made with Python3 to deal with arrays as transactions.
Example:
transactions = [
['Bread', 'Milk'],
['Bread', 'Diaper', 'Beer', 'Eggs'],
['Milk', 'Diaper', 'Beer', 'Coke'],
['Bread', 'Milk', 'Diaper', 'Beer'],
['Bread', 'Milk', 'Diaper', 'Coke']
]
"""
import logging
import multiprocessing as mp
import numpy as np
import time
from collections import Counter
from itertools import chain
from itertools import product
__author__ = "Jackson Antonio do Prado Lima"
__email__ = "[email protected]"
__license__ = "GPL"
__version__ = "1.0"
class GSP:
def __init__(self, raw_transactions):
self.freq_patterns = []
self._pre_processing(raw_transactions)
def _pre_processing(self, raw_transactions):
'''
Prepare the data
Parameters:
raw_transactions: the data that it will be analysed
'''
self.max_size = max([len(item) for item in raw_transactions])
self.transactions = [tuple(list(i)) for i in raw_transactions]
counts = Counter(chain.from_iterable(raw_transactions))
self.unique_candidates = [tuple([k]) for k, c in counts.items()]
def _is_slice_in_list(self, s, l):
len_s = len(s) # so we don't recompute length of s on every iteration
return any(s == l[i:len_s+i] for i in range(len(l) - len_s+1))
def _calc_frequency(self, results, item, minsup):
# The number of times the item appears in the transactions
frequency = len(
[t for t in self.transactions if self._is_slice_in_list(item, t)])
if frequency >= minsup:
results[item] = frequency
return results
def _support(self, items, minsup=0):
'''
The support count (or simply support) for a sequence is defined as
the fraction of total data-sequences that "contain" this sequence.
(Although the word "contains" is not strictly accurate once we
incorporate taxonomies, it captures the spirt of when a data-sequence
contributes to the support of a sequential pattern.)
Parameters
items: set of items that will be evaluated
minsup: minimum support
'''
results = mp.Manager().dict()
pool = mp.Pool(processes=mp.cpu_count())
for item in items:
pool.apply_async(self._calc_frequency,
args=(results, item, minsup))
pool.close()
pool.join()
return dict(results)
def _print_status(self, run, candidates):
logging.debug("""
Run {}
There are {} candidates.
The candidates have been filtered down to {}.\n"""
.format(run,
len(candidates),
len(self.freq_patterns[run-1])))
def search(self, minsup=0.2):
'''
Run GSP mining algorithm
Parameters
minsup: minimum support
'''
assert (0.0 < minsup) and (minsup <= 1.0)
minsup = len(self.transactions) * minsup
# the set of frequent 1-sequence: all singleton sequences
# (k-itemsets/k-sequence = 1) - Initially, every item in DB is a
# candidate
candidates = self.unique_candidates
# scan transactions to collect support count for each candidate
# sequence & filter
self.freq_patterns.append(self._support(candidates, minsup))
# (k-itemsets/k-sequence = 1)
k_items = 1
self._print_status(k_items, candidates)
# repeat until no frequent sequence or no candidate can be found
while len(self.freq_patterns[k_items - 1]) and (k_items + 1 <= self.max_size):
k_items += 1
# Generate candidate sets Ck (set of candidate k-sequences) -
# generate new candidates from the last "best" candidates filtered
# by minimum support
items = np.unique(
list(set(self.freq_patterns[k_items - 2].keys())))
candidates = list(product(items, repeat=k_items))
# candidate pruning - eliminates candidates who are not potentially
# frequent (using support as threshold)
self.freq_patterns.append(self._support(candidates, minsup))
self._print_status(k_items, candidates)
return self.freq_patterns[:-1]