-
Notifications
You must be signed in to change notification settings - Fork 27
Rebuild the example of skfuzzy with fuzzylogic: #47
-
Hi,
I am familiarizing myself with your super nice package. Thanks for making it publicly available.
During my search I came across this example: Tipping Problem
The example has the result 20% tip.
With the code below I get: 2%
I would expect that it is the combination of the rules that makes the difference. What would you recommend to do?
from fuzzylogic.classes import Domain, Set, Rule
from fuzzylogic.functions import R, S, alpha, trapezoid
res = 0.1
food = Domain("food_quality", 0, 10, res = res)
serv = Domain("service_quality", 0, 10, res = res)
tipa = Domain("tip_amount", 0, 25, res = res)
food.lo = S(0, 5)
food.md = alpha(floor = 0, ceiling = 1, func = trapezoid(0, 5, 5, 10))
food.hi = R(5, 10)
serv.lo = S(0, 5)
serv.md = alpha(floor = 0, ceiling = 1, func = trapezoid(0, 5, 5, 10))
serv.hi = R(5, 10)
tipa.lo = S(0, 13)
tipa.md = alpha(floor = 0, ceiling = 1, func = trapezoid(0, 13, 13, 25))
tipa.hi = R(13, 25)
rules = Rule({
(food.hi, serv.hi): tipa.hi,
(food.lo, serv.lo): tipa.lo,
(serv.md, ): tipa.md,
})
values = {food: 6.5, serv: 9.8}
print(R1(values), R2(values), R3(values), rules(values))
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 3 comments 21 replies
-
Hi and thanks you!
The first thing I'm noticing is their use of trimf, which is the triangular function which should correspond to fuzzylogic.functions.triangular (at least one would rightfully expect so!).
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
The next thing I'm noticing is x_qual = np.arange(0, 11, 1) which corresponds to your food = Domain("food_quality", 0, 10, res = res) (changing resolution and domain may change the end result quite a bit since weights are shifted)
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Next step would be to visually check if the plots match your expectations...
Beta Was this translation helpful? Give feedback.
All reactions
-
Ah, interesting. They have an fuzz.interp_membership function - smart. Let's steal that 😁 (probably just a wrapper for a np interpolation, but still)
Beta Was this translation helpful? Give feedback.
All reactions
-
👀 1
-
You're using the Rule class to map the use of OR in their code? I'd immediately think of fuzzylogic.combinators.MAX when I read OR... or the | operator between fuzzy-functions, which maps to MAX.
Beta Was this translation helpful? Give feedback.
All reactions
-
Next step would be to visually check if the plots match your expectations...
Food:
image
Service
image
Tip:
image
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
I find it a bit hard to read their mix of rules, plots and functions, tbh.. but here we go
Beta Was this translation helpful? Give feedback.
All reactions
-
I think I found the issue.
from fuzzylogic.classes import Domain, Rule
from fuzzylogic.functions import R, S, triangular
res = 1
food = Domain("food_quality", 0, 10, res=res)
serv = Domain("service_quality", 0, 10, res=res)
tip = Domain("tip_amount", 0, 25, res=res)
food.lo = S(0, 5)
food.md = triangular(0, 10)
food.hi = R(5, 10)
serv.lo = S(0, 5)
serv.md = triangular(0, 10)
serv.hi = R(5, 10)
tip.lo = S(0, 13)
tip.md = triangular(0, 25)
tip.hi = R(13, 25)
rules = Rule({
(food.lo, serv.lo): tip.lo,
(food.md, serv.md): tip.md,
(food.hi, serv.hi): tip.hi,
})
values = {food: 6.5, serv: 9.8}
print(rules(values))
Returns 19.513574660633484 which is close to the expected 20% - it seems the resolution indeed was the culprit - which means the interpolation actually makes all the difference.
(Now looking at my code and comparing it to the original makes me wonder if I missed anything, it's so much more concise.. 🤔)
Beta Was this translation helpful? Give feedback.
All reactions
-
While, of course, I hope that my code is correct, it's possible that I made a mistake. That's why I rewrote it - to better scrutinize and improve.
My code does the following:
- for every domain:value in the input calculate the membership values for all relevant fuzzy sets
- for every IF-THEN rule take the min (AND) of the membership values and associate the THEN fuzzy set with the result as weight
- calculate the weighted average for the cog of all THEN fuzzy sets as dimensionless index on the domain array
- adjust for the limits and resolution of the domain to translate the index to the actual end value.
I guess it shows I never really cared much for defuzzification and put my emphasis on correctness and efficiency of the membership functions and combinators... 🤔
Beta Was this translation helpful? Give feedback.
All reactions
-
Hey,
thanks for the explanation. I cannot claim to being able to evaluate your code, but it is read-, and understandable. How it works in the bigger picture is yet beyond my scope. But I will look further into the options your package offers for me =D
Beta Was this translation helpful? Give feedback.
All reactions
-
😄 1
-
Heya,
hope you're doing great.
I played around with your fuzzylogic package in a separate python environment (called fuzzy). Now that my main project is far enough to add fuzzy logic to it, i re-installed your package in a different env (called gis). The same example we posted above is not working in the gis environment. Neither does the new one. But it still works in the fuzzy.
Thus either there is a bad interaction betwenn different packages in the gis environment or you changed something in your code that causes that error (code see below). What do you think?
(PS: does github not offer to have collabseable sections in posts?)
from fuzzylogic.classes import Domain, Rule
from fuzzylogic.functions import R, S, triangular
res = 1
food = Domain("food_quality", 0, 10, res=res)
serv = Domain("service_quality", 0, 10, res=res)
tip = Domain("tip_amount", 0, 25, res=res)
food.lo = S(0, 5)
food.md = triangular(0, 10)
food.hi = R(5, 10)
serv.lo = S(0, 5)
serv.md = triangular(0, 10)
serv.hi = R(5, 10)
tip.lo = S(0, 13)
tip.md = triangular(0, 25)
tip.hi = R(13, 25)
rules = Rule({
(food.lo, serv.lo): tip.lo,
(food.md, serv.md): tip.md,
(food.hi, serv.hi): tip.hi,
})
values = {food: 6.5, serv: 9.8}
print(rules(values))
ohalala
Traceback (most recent call last):
Cell In[13], line 30
print(rules(values))
File ~\AppData\Local\miniconda3\envs\gis\Lib\site-packages\fuzzylogic\classes.py:447 in __call__
index = sum(v.center_of_gravity * x for v, x in weights) / sum(x for v, x in weights)
File ~\AppData\Local\miniconda3\envs\gis\Lib\site-packages\fuzzylogic\classes.py:447 in <genexpr>
index = sum(v.center_of_gravity * x for v, x in weights) / sum(x for v, x in weights)
TypeError: unsupported operand type(s) for *: 'method' and 'float'
Beta Was this translation helpful? Give feedback.
All reactions
-
That's the old (fixed, but not released) bug. It's just missing a () at v.center_of_gravity(). I really should push a release. Possibly later today.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Oh nos. I am sorry I should have known... I once corrected it.
Beta Was this translation helpful? Give feedback.
All reactions
-
😄 1