Skip to content

Commit 96188af

Browse files
authored
Merge pull request #472 from pallamadhavi/main
Automated Testing
2 parents 06845c0 + a026060 commit 96188af

21 files changed

Lines changed: 1111 additions & 4 deletions
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# Copyright (C) 2021 Rage Uday Kiran
2+
#
3+
# This program is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
15+
16+
from abc import ABC as _ABC, abstractmethod as _abstractmethod
17+
import time as _time
18+
import csv as _csv
19+
import pandas as _pd
20+
from collections import defaultdict as _defaultdict
21+
from itertools import combinations as _c
22+
import os as _os
23+
import os.path as _ospath
24+
import psutil as _psutil
25+
import validators as _validators
26+
from urllib.request import urlopen as _urlopen
27+
import sys as _sys
28+
import math as _math
29+
30+
31+
class _correlatedPatterns(_ABC):
32+
"""
33+
:Description: This abstract base class defines the variables and methods that every correlated pattern mining algorithm must
34+
employ in PAMI
35+
36+
:Attributes:
37+
38+
iFile : str
39+
Input file name or path of the input file
40+
minSup: integer or float or str
41+
The user can specify minSup either in count or proportion of database size.
42+
If the program detects the data type of minSup is integer, then it treats minSup is expressed in count.
43+
Otherwise, it will be treated as float.
44+
Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float
45+
minAllConf: float
46+
The user given minimum all confidence Ratio(should be in range of 0 to 1)
47+
sep : str
48+
This variable is used to distinguish items from one another in a transaction. The default seperator is tab space or \t.
49+
However, the users can override their default separator
50+
startTime:float
51+
To record the start time of the algorithm
52+
endTime:float
53+
To record the completion time of the algorithm
54+
finalPatterns: dict
55+
Storing the complete set of patterns in a dictionary variable
56+
oFile : str
57+
Name of the output file to store complete set of correlated patterns
58+
memoryUSS : float
59+
To store the total amount of USS memory consumed by the program
60+
memoryRSS : float
61+
To store the total amount of RSS memory consumed by the program
62+
63+
:Methods:
64+
65+
startMine()
66+
Calling this function will start the actual mining process
67+
getPatterns()
68+
This function will output all interesting patterns discovered by an algorithm
69+
save(oFile)
70+
This function will store the discovered patterns in an output file specified by the user
71+
getPatternsAsDataFrame()
72+
The function outputs the patterns generated by an algorithm as a data frame
73+
getMemoryUSS()
74+
This function outputs the total amount of USS memory consumed by a mining algorithm
75+
getMemoryRSS()
76+
This function outputs the total amount of RSS memory consumed by a mining algorithm
77+
getRuntime()
78+
This function outputs the total runtime of a mining algorithm
79+
80+
"""
81+
82+
def __init__(self, iFile, minSup, minAllConf, sep="\t"):
83+
"""
84+
:param iFile: Input file name or path of the input file
85+
:type iFile: str
86+
:param minSup: The user can specify minSup either in count or proportion of database size.
87+
If the program detects the data type of minSup is integer, then it treats minSup is expressed in count.
88+
Otherwise, it will be treated as float.
89+
Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float
90+
:type minSup: int or float or str
91+
:param minAllConf: The user given minimum all confidence Ratio(should be in range of 0 to 1)
92+
:type minAllConf :float
93+
:param sep: separator used to distinguish items from each other. The default separator is tab space. However, users can override the default separator
94+
:type sep: str
95+
"""
96+
97+
self._iFile = iFile
98+
self._sep = sep
99+
self._minSup = minSup
100+
self._minAllConf = minAllConf
101+
self._finalPatterns = {}
102+
self._oFile = str()
103+
self._memoryRSS = float()
104+
self._memoryUSS = float()
105+
self._startTime = float()
106+
self._endTime = float()
107+
108+
109+
@_abstractmethod
110+
def startMine(self):
111+
"""
112+
Code for the mining process will start from this function
113+
"""
114+
115+
pass
116+
117+
@_abstractmethod
118+
def getPatterns(self):
119+
"""
120+
Complete set of correlated patterns generated will be retrieved from this function
121+
"""
122+
123+
pass
124+
125+
@_abstractmethod
126+
def save(self, oFile):
127+
"""
128+
Complete set of correlated patterns will be saved in to an output file from this function
129+
:param oFile: Name of the output file
130+
:type oFile: csv file
131+
"""
132+
133+
pass
134+
135+
@_abstractmethod
136+
def getPatternsAsDataFrame(self):
137+
"""
138+
Complete set of correlated patterns will be loaded in to data frame from this function
139+
"""
140+
141+
pass
142+
143+
@_abstractmethod
144+
def getMemoryUSS(self):
145+
"""
146+
Total amount of USS memory consumed by the program will be retrieved from this function
147+
"""
148+
149+
pass
150+
151+
@_abstractmethod
152+
def getMemoryRSS(self):
153+
"""
154+
Total amount of RSS memory consumed by the program will be retrieved from this function
155+
"""
156+
157+
pass
158+
159+
160+
@_abstractmethod
161+
def getRuntime(self):
162+
"""
163+
Total amount of runtime taken by the program will be retrieved from this function
164+
"""
165+
166+
pass
167+
168+
@_abstractmethod
169+
def printResults(self):
170+
"""
171+
To print the results of execution.
172+
"""
173+
174+
pass
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pandas as pd
2+
from PAMI.correlatedPattern.basic.CoMine import CoMine as alg
3+
import warnings
4+
5+
warnings.filterwarnings("ignore")
6+
7+
# CoMine algorithm from PAMI
8+
def test_pami(dataset, min_sup=0.2, min_all_conf=0.2):
9+
dataset = [",".join(i) for i in dataset]
10+
with open("sample.csv", "w+") as f:
11+
f.write("\n".join(dataset))
12+
obj = alg(iFile="sample.csv", minSup=min_sup, minAllConf=min_all_conf, sep=',')
13+
obj.mine()
14+
res = obj.getPatternsAsDataFrame()
15+
res["Patterns"] = res["Patterns"].apply(lambda x: x.split())
16+
res["Support"] = res["Support"].apply(lambda x: x / len(dataset))
17+
pami = res
18+
return pami
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pandas as pd
2+
from PAMI.correlatedPattern.basic.CoMinePlus import CoMinePlus as alg
3+
import warnings
4+
5+
warnings.filterwarnings("ignore")
6+
7+
# CoMine algorithm from PAMI
8+
def test_pami(dataset, min_sup=0.2, min_all_conf=0.2):
9+
dataset = [",".join(i) for i in dataset]
10+
with open("sample.csv", "w+") as f:
11+
f.write("\n".join(dataset))
12+
obj = alg(iFile="sample.csv", minSup=min_sup, minAllConf=min_all_conf, sep=',')
13+
obj.mine()
14+
res = obj.getPatternsAsDataFrame()
15+
res["Patterns"] = res["Patterns"].apply(lambda x: x.split())
16+
res["Support"] = res["Support"].apply(lambda x: x / len(dataset))
17+
pami = res
18+
return pami
19+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import unittest
2+
from gen import generate_transactional_dataset
3+
from automated_test_CoMine import test_pami
4+
import warnings
5+
6+
warnings.filterwarnings("ignore")
7+
8+
class TestExample(unittest.TestCase):
9+
10+
def test_num_patterns(self):
11+
for _ in range(3):
12+
num_distinct_items = 20
13+
num_transactions = 1000
14+
max_items_per_transaction = 20
15+
items = ["item-{}".format(i) for i in range(1, num_distinct_items + 1)]
16+
dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
17+
18+
pami = test_pami(dataset)
19+
# As we don't have a second method to compare, we just verify the length of pami
20+
self.assertGreater(len(pami), 0, "No patterns were generated by CoMine")
21+
22+
print("3 test cases for number of patterns have been passed")
23+
24+
def test_equality(self):
25+
for _ in range(3):
26+
num_distinct_items = 20
27+
num_transactions = 1000
28+
max_items_per_transaction = 20
29+
items = ["item-{}".format(i) for i in range(1, num_distinct_items + 1)]
30+
dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
31+
32+
pami = test_pami(dataset)
33+
# Since we have no second method to compare, we just verify the patterns are generated
34+
pami_patterns = sorted(list(pami["Patterns"]))
35+
self.assertTrue(len(pami_patterns) > 0, "No patterns were generated by CoMine")
36+
37+
print("3 test cases for Patterns equality are passed")
38+
39+
def test_support(self):
40+
for _ in range(3):
41+
num_distinct_items = 20
42+
num_transactions = 1000
43+
max_items_per_transaction = 20
44+
items = ["item-{}".format(i) for i in range(1, num_distinct_items + 1)]
45+
dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
46+
47+
pami = test_pami(dataset)
48+
# Since we have no second method to compare, we just verify the support values are generated
49+
pami.sort_values(by="Support", inplace=True)
50+
ps = list(pami["Support"])
51+
for support in ps:
52+
self.assertTrue(support > 0, "Support value should be greater than 0")
53+
54+
print("3 test cases for support equality are passed")
55+
56+
if __name__ == '__main__':
57+
unittest.main()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import unittest
2+
from gen import generate_transactional_dataset
3+
from automated_test_CoMinePlus import test_pami
4+
import warnings
5+
6+
warnings.filterwarnings("ignore")
7+
8+
class TestExample(unittest.TestCase):
9+
def test_num_patterns(self):
10+
for _ in range(3):
11+
num_distinct_items = 20
12+
num_transactions = 1000
13+
max_items_per_transaction = 20
14+
items = ["item-{}".format(i) for i in range(1, num_distinct_items + 1)]
15+
dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
16+
pami = test_pami(dataset)
17+
self.assertGreater(len(pami), 0, "No patterns were generated by PAMI")
18+
print("3 test cases for number of patterns have been passed")
19+
20+
def test_equality(self):
21+
for _ in range(3):
22+
num_distinct_items = 20
23+
num_transactions = 1000
24+
max_items_per_transaction = 20
25+
items = ["item-{}".format(i) for i in range(1, num_distinct_items + 1)]
26+
dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
27+
pami = test_pami(dataset)
28+
pami_patterns = sorted(list(pami["Patterns"]))
29+
self.assertTrue(len(pami_patterns) > 0, "No patterns were generated by PAMI")
30+
print("3 test cases for Patterns equality are passed")
31+
32+
def test_support(self):
33+
for _ in range(3):
34+
num_distinct_items = 20
35+
num_transactions = 1000
36+
max_items_per_transaction = 20
37+
items = ["item-{}".format(i) for i in range(1, num_distinct_items + 1)]
38+
dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
39+
pami = test_pami(dataset)
40+
pami.sort_values(by="Support", inplace=True)
41+
ps = list(pami["Support"])
42+
for support in ps:
43+
self.assertTrue(support > 0, "Support value should be greater than 0")
44+
print("3 test cases for support equality are passed")
45+
46+
if __name__ == '__main__':
47+
unittest.main()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import random
2+
import warnings
3+
4+
warnings.filterwarnings("ignore")
5+
6+
def generate_transactional_dataset(num_transactions, items, max_items_per_transaction):
7+
dataset = []
8+
for _ in range(num_transactions):
9+
num_items = random.randint(1, max_items_per_transaction)
10+
transaction = random.sample(items, num_items)
11+
dataset.append(transaction)
12+
return dataset
13+
14+
# Example usage:
15+
# num_distinct_items=20
16+
# num_transactions = 1000
17+
# max_items_per_transaction = 20
18+
# items=["item-{}".format(i) for i in range(1,num_distinct_items+1)]
19+
# dataset = generate_transactional_dataset(num_transactions, items, max_items_per_transaction)
20+
# print(dataset)

0 commit comments

Comments
 (0)