The Tipping Problem / defuzzication 2 inputs?

955 views
Skip to first unread message

Stavros Anastasiadis

unread,
Apr 28, 2014, 6:18:35 AM4/28/14
to scikit...@googlegroups.com
I trying to solve the classic Tipping Problem of Matlab example with scikit-fuzzy.
So far i have:
The rule system -Tipping Problem
  • If service is poor or the food is rancid, THEN tip is cheap
  • If service is good, THEN tip is average
  • If service is excellent or food is delicious, THEN tip is generous
Step 0: Initial Imports
import numpy as np
import skfuzzy as fuzz

Step 1 : Fuzzify Input / Output 
#Input  Variables have the same domain/ Universe functions
service = np.arange(0,11,1)
food    = np.arange(0,11,1)
#Output Variables Domain
tip = np.arange(0,101,1) 

#Input Membership Functions
#Service
ser_p = fuzz.gaussmf(service ,0,1.5)
ser_g = fuzz.gaussmf(service ,5,1.5)
ser_e = fuzz.gaussmf(service ,10,1.5)
#Food
foo_r = fuzz.trapmf(food , [0, 0, 1, 3])
foo_d = fuzz.gaussmf(food ,10,1.5)

#Output tip
tip_ch  = fuzz.trimf(tip, [0, 15, 30])
tip_ave = fuzz.trimf(tip, [25, 45, 70])
tip_gen = fuzz.trimf(tip, [60, 80, 100])

Step 2: Apply Fuzzy Operator for antecedent part
#Rule 1 antecedent part
R1_antecedent = fuzz.fuzzy_or(service,ser_p,food,foo_r)
#Rule 3 antecedent part
R3_antecedent = fuzz.fuzzy_or(service,ser_e,food,foo_d)

Step 3: Apply implication Method
R1 =  fuzz.relation_product(R1_antecedent[1],tip_ch)
R2 =  fuzz.relation_product(ser_g,tip_ave)
R3 =  fuzz.relation_product(R3_antecedent[1],tip_gen)

Step 4: Aggregate all outputs 
R_combined = np.fmax(R1, np.fmax(R2, R3))

Step 5: Defuzzication 
fuzz.defuzz(out_d, R_combined[service == 2], 'centroid')

The problem is that i have 2 inputs (Service and Food), How I cam use defuzzication with 2 input like fuzz.defuzz(out_d, R_combined[service == 2 and food == 4], 'centroid')
Is my procedure wrong? 

Kind Regards
Stavros 

JDWarner

unread,
Apr 29, 2014, 1:31:10 AM4/29/14
to scikit...@googlegroups.com

Hi Stavros,

That’s a very nice write-up! I think I can illustrate where things went wrong. It’s a subtle mistake that is easy to make when more than one fuzzy universes share the same length.

The problem is in Step 2. When you combine two membership functions with OR, you must take care. fuzz.fuzzy_or allows different universes to be combined, but this is not always meaningful. It’s written this way mostly to allow two fuzzy membership functions which correspond to the same universe variable (but in slightly different overlapping regions, or at different resolutions) to be combined. When you use it to combine membership functions from the universes “food” and “service”, you lose the ability to input these variables separately.

To solve this problem you need a slightly different approach - which turns out to be a bit simpler. Step 1 is fine; I’ll modify starting at Step 2.

Step 2: Apply fuzzy inputs to membership functions
I recommend the use of fuzz.interp_membership so you can input arbitrary values on the input universe. If you wanted service == 4.36 and food == 7.42, this is possible with fuzz.interp_membership but will generate errors if you simply did foo_r[food == 7.42]. For existing values, the results are equivalent.

# Here I'll use your example service == 2 and food == 4
# These return a single value, which is combined using the rules in Step 3 
#   and operates on tip membership functions in Step 4
food_1 = fuzz.interp_membership(food, foo_r, 4.)
food_3 = fuzz.interp_membership(food, foo_r, 4.)
service_1 = fuzz.interp_membership(service, ser_p, 2)
service_2 = fuzz.interp_membership(service, ser_g, 2)
service_3 = fuzz.interp_membership(service, ser_e, 2)

Step 3a: Determine the weight for each rule from fuzzy antecedents (first half of “Apply Implication Method” in Matlab tutorial)

# First rule is OR - this is a max operator
rule1 = np.fmax(food_1, service_1)  # Doable with inbuilt Python max(), but np.fmax is more general
rule2 = service_2  # No combination, this is just passed
rule3 = np.fmax(food_3, service_3)

Step 3b: Apply implication operator (min or product - these are simple, not inbuilt operators)

# Product is simple multiplication of weight w/fuzzy membership function
# min is np.fmin(weight, membership)
# Here I use product because that appears to be your preference
imp1 = rule1 * tip_ch
imp2 = rule2 * tip_ave
imp3 = rule3 * tip_gen

Step 4: Aggregate all outputs

This simply combines the three results from Step 3b; the actual command is the same as your Step 4 (using nested np.fmax)

aggregate_membership = np.fmax(imp1, np.fmax(imp2, imp3))

Step 5: Defuzzify to determine tip

tip = fuzz.defuzz(tip, aggregate_membership, 'centroid')
# My result: 19.4

The result of 19.4 seems like a somewhat high tip for relatively poor service (2) and food (4), but I think this is because your tip universe variable is operating on the range [0, 101]. If this were scaled to a more reasonable tip range of [0, 25] in units of bill percent, the result would be close to 5% - a low tip for a poor experience!

This may seem slightly more complicated than before, but I hope you can see how it’s entirely possible to automate this programmatically in a function which would accept service and food as inputs and return a tip percentage. Let me know if anything was unclear.

Hope that helps,
Josh

Lara

unread,
Jun 23, 2014, 1:06:47 PM6/23/14
to scikit...@googlegroups.com
Hi Mr.Warner and Stavros,

is the function interp_membership for fuzzification? Do i get the value of membership function, if for example service_poor = 4 ? What make the step: service_1 = fuzz.interp_membership(service, ser_p, 2)?

Thank you in advance for your answer!

JDWarner

unread,
Jun 25, 2014, 12:32:22 AM6/25/14
to scikit...@googlegroups.com
Hi Lara,

The function `interp_membership` operates on a fuzzy set, it does not make a set fuzzy. Fuzzy sets are defined on a *universe variable*, often at fairly sparse locations (e.g., [1, 3, 5, ...]). In many fuzzy applications, it might be desired to know the membership value at some point which doesn't exactly fall on one of the universe locations. For example, you might have a sensor with input 3.457.

Without `interp_membership` the only values which will work are the exact universe locations. The purpose of this function is to allow you to determine the output of the system (the tip percent, in this case) for inputs between existing values on the universe variable.

In your example there would be no need for `interp_membership` if service_poor = 4, because 4 is a defined location on the fuzzy universe. But if you suddenly needed to recalculate your tip for service_poor = 4.25, then you would. My recommendation to use `interp_membership` is basically so you can obtain results for a diverse array of inputs.

Hope that helps,

Josh

Yasmine ben attia

unread,
Oct 8, 2015, 1:13:21 PM10/8/15
to scikit-fuzzy
Hello Mr.Warner,

I'm dealing with a more complex example where I have 21 rules. What shall I do to aggregate them all?

Thank you in advance
Reply all
Reply to author
Forward
0 new messages