├── twd ├── __init__.py └── twd.py ├── LICENSE ├── test_twd.py └── README.md /twd/__init__.py: -------------------------------------------------------------------------------- 1 | # __init__.py 2 | 3 | from .twd import TWD 4 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Sergio S. Ribeiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test_twd.py: -------------------------------------------------------------------------------- 1 | from twd import TWD 2 | 3 | dt = [["n","y","high","y"], 4 | ["y","n","high","y"], 5 | ["y","y","very high","y"], 6 | ["n","y","normal","n"], 7 | ["y","n","high","n"], 8 | ["n","y","very high","y"]] 9 | 10 | o3wd = TWD(dt,["Headache","Muscle Pain","Temperature"]) 11 | 12 | print("U => ",o3wd.getU()) 13 | print("X={x| Flu(x)=y} =>",o3wd.getX("y")) 14 | print("Va(Headache)",o3wd.getVa("Headache")) 15 | print("Va(Muscle Pain)",o3wd.getVa("Muscle Pain")) 16 | print("Va(Temperature)",o3wd.getVa("Temperature")) 17 | print("Vd",o3wd.getVd()) 18 | print("Va",o3wd.getVa()) 19 | print("IND(A)",o3wd.getIND()) 20 | print("IND(Headache)",o3wd.getIND(["Headache"])) 21 | print("IND(Headache,Muscle Pain)",o3wd.getIND(["Headache","Muscle Pain"])) 22 | print("IND(Muscle Pain)",o3wd.getIND(["Muscle Pain"])) 23 | print("IND(Temperature)",o3wd.getIND(["Temperature"])) 24 | print("IND(Headache,Temperature)",o3wd.getIND(["Headache","Temperature"])) 25 | print("lowerXA =>",o3wd.getLowerAX(o3wd.getX("y"),o3wd.getIND())) 26 | print("upperXA =>",o3wd.getUpperAX(o3wd.getX("y"),o3wd.getIND())) 27 | print("POS(X)",o3wd.getPOSX(o3wd.getX("y"),o3wd.getIND())) 28 | print("BND(X)",o3wd.getBNDX(o3wd.getX("y"),o3wd.getIND())) 29 | print("NEG(X)",o3wd.getNEGX(o3wd.getX("y"),o3wd.getIND())) 30 | print("Precision of Approximation: ",o3wd.precision(o3wd.getX("y"),o3wd.getIND())) 31 | print("Quality of Approximation: ",o3wd.quality(o3wd.getX("y"),o3wd.getIND())) 32 | print("Roughness: ",o3wd.roughness(o3wd.getX("y"),o3wd.getIND())) 33 | print("") 34 | print("Rules") 35 | print(o3wd.getRules(o3wd.getPOSX(o3wd.getX("y"),o3wd.getIND()))) 36 | print("") 37 | print("Reduction:",o3wd.getReduct()) 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TWD 2 | A Python library for Three Way Decision and Rough Set Theory. 3 | 4 | ## Citation 5 | 6 | ``` 7 | @inproceedings{ribeiro2019toward, 8 | title={Toward a three-way image classification model: A case study on corn grain images}, 9 | author={Ribeiro, Sergio Silva and Yao, JingTao}, 10 | booktitle={2019 IEEE International Symposium on Multimedia (ISM)}, 11 | pages={177--1776}, 12 | year={2019}, 13 | organization={IEEE} 14 | } 15 | ``` 16 | ## Getting Started 17 | #### Dependencies 18 | There is not dependecy for this library 19 | 20 | #### Installation 21 | ``` 22 | pip install twd 23 | ``` 24 | #### Sample Usage 25 | For this example we will assume the following Decision System/Table (DS): 26 | 27 | | Headache | Muscle Pain | Temperature | Flu | 28 | | -------- | ----------- | ----------- | --- | 29 | | n | y | high | y | 30 | | y | n | high | y | 31 | | y | y | very high | y | 32 | | n | y | normal | n | 33 | | y | n | high | n | 34 | | n | y | very high | y | 35 | 36 | The sample usage considering the mentioned DS is: 37 | 38 | ```sh 39 | from twd import TWD 40 | 41 | dt = [["n","y","high","y"], 42 | ["y","n","high","y"], 43 | ["y","y","very high","y"], 44 | ["n","y","normal","n"], 45 | ["y","n","high","n"], 46 | ["n","y","very high","y"]] 47 | 48 | o3wd = TWD(dt,["Headache","Muscle Pain","Temperature"]) 49 | 50 | print("U => ",o3wd.getU()) 51 | print("X={x| Flu(x)=y} =>",o3wd.getX("y")) 52 | print("Va(Headache)",o3wd.getVa("Headache")) 53 | print("Va(Muscle Pain)",o3wd.getVa("Muscle Pain")) 54 | print("Va(Temperature)",o3wd.getVa("Temperature")) 55 | print("Vd",o3wd.getVd()) 56 | print("Va",o3wd.getVa()) 57 | print("IND(A)",o3wd.getIND()) 58 | print("IND(Headache)",o3wd.getIND(["Headache"])) 59 | print("IND(Headache,Muscle Pain)",o3wd.getIND(["Headache","Muscle Pain"])) 60 | print("IND(Muscle Pain)",o3wd.getIND(["Muscle Pain"])) 61 | print("IND(Temperature)",o3wd.getIND(["Temperature"])) 62 | print("IND(Headache,Temperature)",o3wd.getIND(["Headache","Temperature"])) 63 | print("lowerXA =>",o3wd.getLowerAX(o3wd.getX("y"),o3wd.getIND())) 64 | print("upperXA =>",o3wd.getUpperAX(o3wd.getX("y"),o3wd.getIND())) 65 | print("POS(X)",o3wd.getPOSX(o3wd.getX("y"),o3wd.getIND())) 66 | print("BND(X)",o3wd.getBNDX(o3wd.getX("y"),o3wd.getIND())) 67 | print("NEG(X)",o3wd.getNEGX(o3wd.getX("y"),o3wd.getIND())) 68 | print("Precision of Approximation: ",o3wd.precision(o3wd.getX("y"),o3wd.getIND())) 69 | print("Quality of Approximation: ",o3wd.quality(o3wd.getX("y"),o3wd.getIND())) 70 | print("Roughness: ",o3wd.roughness(o3wd.getX("y"),o3wd.getIND())) 71 | print("") 72 | print("Rules") 73 | print(o3wd.getRules(o3wd.getPOSX(o3wd.getX("y"),o3wd.getIND()))) 74 | print("") 75 | print("Reduction:",o3wd.getReduct()) 76 | ``` 77 | ## Features 78 | - Indiscernibility 79 | - Set Approximation 80 | - Precision of Approximation 81 | - Quality of Approximation 82 | - Roughness 83 | - Rules 84 | - Reducts 85 | 86 | ## License 87 | 88 | MIT 89 | -------------------------------------------------------------------------------- /twd/twd.py: -------------------------------------------------------------------------------- 1 | # Author: Sergio Ribeiro (2021) 2 | 3 | class TWD: 4 | def __init__(self, DS=[],A=[]): 5 | self.DS = DS 6 | self.A = A 7 | 8 | def getU(self): 9 | return set([o for o in range(len(self.DS))]) 10 | 11 | def getX(self,Vd): 12 | X = [] 13 | for o in range(len(self.DS)): 14 | if self.DS[o][len(self.A)]==Vd: 15 | X.append(o) 16 | return set(X) 17 | 18 | def getVa(self,a=""): 19 | Va = [] 20 | if a in self.A: 21 | Va = set([i[self.A.index(a)] for i in self.DS]) 22 | elif a=="": 23 | for a in self.A: 24 | Va.append( set([i[self.A.index(a)] for i in self.DS]) ) 25 | return Va 26 | 27 | def getVd(self): 28 | return set([i[len(self.A)] for i in self.DS]) 29 | 30 | def getIND(self,P=[]): 31 | IND = [] 32 | unique = [] 33 | 34 | if P == []: 35 | P = self.A 36 | 37 | for o in range(len(self.DS)): 38 | Vo = [] 39 | for a in self.A: 40 | if a in P: 41 | Vo.append( self.DS[o][self.A.index(a)] ) 42 | if Vo not in unique: 43 | unique.append(Vo) 44 | IND.append([o]) 45 | elif Vo in unique: 46 | i = unique.index(Vo) 47 | if isinstance(IND[i], list): 48 | IND[i].append(o) 49 | else: 50 | IND[i]=[IND[i]] 51 | IND[i].append(o) 52 | return IND 53 | 54 | def getLowerAX(self,X,IND): 55 | lowerAX = [] 56 | for i in range(len(IND)): 57 | if set(IND[i]).issubset(X): 58 | for n in range(len(IND[i])): 59 | lowerAX.append(IND[i][n]) 60 | return set(lowerAX) 61 | 62 | def getUpperAX(self,X,IND): 63 | upperAX = [] 64 | for i in range(len(IND)): 65 | if len(set(IND[i]).intersection(set(X)))>0: 66 | for n in range(len(IND[i])): 67 | upperAX.append(IND[i][n]) 68 | return set(upperAX) 69 | 70 | def getPOSX(self,X,IND): 71 | return self.getLowerAX(X,IND) 72 | 73 | def getBNDX(self,X,IND): 74 | return self.getUpperAX(X,IND) - self.getLowerAX(X,IND) 75 | 76 | def getNEGX(self,X,IND): 77 | return self.getU()-(self.getPOSX(X,IND).union(self.getBNDX(X,IND))) 78 | 79 | def getRules(self,region,P=[]): 80 | if P == []: 81 | P = self.A 82 | rules = "" 83 | count = 0 84 | for i in region: 85 | count+=1 86 | rule = "" 87 | for n in range(len(self.A)): 88 | if not rule: 89 | rule += P[n] + " == " + str(self.DS[i][n]) 90 | else: 91 | if n > 0: 92 | rule += " AND " 93 | rule += P[n] + " == " + str(self.DS[i][n]) 94 | if rule not in rules: 95 | rules += "\n ["+str(count)+"] " + rule 96 | return rules 97 | 98 | def precision(self,X,IND): 99 | return len(self.getLowerAX(X,IND))/len(self.getUpperAX(X,IND)) 100 | 101 | def quality(self,X,IND): 102 | return (len(self.getPOSX(X,IND))+len(self.getNEGX(X,IND)))/len(self.getU()) 103 | 104 | def roughness(self,X,IND): 105 | return len(self.getBNDX(X,IND))/len(self.getU()) 106 | 107 | def comb(self,inp, temp=[], ans=[]): 108 | for i in range(len(inp)): 109 | current = inp[i] 110 | remaining = inp[i + 1:] 111 | temp.append(current) 112 | ans.append(list(temp)) 113 | self.comb(remaining, temp, ans) 114 | temp.pop() 115 | return ans 116 | 117 | def getReduct(self): 118 | ind = self.getIND() 119 | red = [] 120 | comb = self.comb(self.A) 121 | for a in comb: 122 | if self.getIND(a) == ind and a != self.A: 123 | red.append(a) 124 | return red 125 | 126 | 127 | --------------------------------------------------------------------------------