How to efficiently plot a fuzzy surface using R's sets library

764 views Asked by At

In R, how can you best plot a fuzzy surface in a 3D plot using the sets package for fuzzy logic? The service variable and food variable should be they x and y axis, and the z axis should be the centroid found from defuzzifying the fuzzy inference variable.

I am a beginner in R that tried using expand.grid to plot 4,000 points of a fuzzy surface, and my computer disk went to 100% and stayed that way even after 2 restarts. I will intentionally not show you the code I wrote, for the safety of your computer.

This example system from their documents would be a good starting point. Can you help me plot the results? Thanks.

library(sets)
# set universe
sets_options("universe", seq(from = 0, to = 25, by = 1))

# set up fuzzy variables
variables <-
  set(service = fuzzy_partition(varnames = c(poor = 0, good = 5, excellent = 10), sd = 1.5),
      food = fuzzy_variable(rancid = fuzzy_trapezoid(corners = c(-2, 0, 2, 4)),
                            delicious = fuzzy_trapezoid(corners = c(7, 9, 11, 13))),
      tip = fuzzy_partition(varnames = c(cheap = 5, average = 12.5, generous = 20),
                            FUN = fuzzy_cone, radius = 5)
  )

# set up rules
rules <-
  set(
    fuzzy_rule(service %is% poor || food %is% rancid, tip %is% cheap),
    fuzzy_rule(service %is% good, tip %is% average),
    fuzzy_rule(service %is% excellent || food %is% delicious, tip %is% generous)
  )

# combine to a system
system <- fuzzy_system(variables, rules)
print(system)
plot(system) ## plots variables

# do inference
fi <- fuzzy_inference(system, list(service = 3, food = 8.123))

# plot resulting fuzzy set
plot(fi)

# defuzzify
print(gset_defuzzify(fi, "centroid"))

# reset universe
sets_options("universe", NULL)
1

There are 1 answers

0
Soson On

I decided to keep experimenting despite the harm I caused my computer. This code below works, but I'd still appreciate an answer from a more experienced programmer.

# Please help me take this example from the docs and make a nice 3d plot
options(show.error.locations = TRUE)

library(sets)
## set universe
sets_options("universe", seq(from = 0, to = 25, by = 1))

## set up fuzzy variables
variables <-
  set(service = fuzzy_partition(varnames = c(poor = 0, good = 5, excellent = 10), sd = 1.5),
      food = fuzzy_variable(rancid = fuzzy_trapezoid(corners = c(-2, 0, 2, 4)),
                            delicious = fuzzy_trapezoid(corners = c(7, 9, 11, 13))),
      tip = fuzzy_partition(varnames = c(cheap = 5, average = 12.5, generous = 20),
                            FUN = fuzzy_cone, radius = 5)
  )

## set up rules
rules <-
  set(
    fuzzy_rule(service %is% poor || food %is% rancid, tip %is% cheap),
    fuzzy_rule(service %is% good, tip %is% average),
    fuzzy_rule(service %is% excellent || food %is% delicious, tip %is% generous)
  )

## combine to a system
system <- fuzzy_system(variables, rules)
print(system)
plot(system) ## plots variables

## do inference
fi <- fuzzy_inference(system, list(service = 3, food = 8))

## plot resulting fuzzy set
#plot(fi)

# define a function to compute a tip given a row 
# that has a service column and food column
defuzzify <- function(row){
  fi <- fuzzy_inference(system, list(service = row$service, food = row$food))
  gset_defuzzify(fi, "centroid")
}

# create a dataframe with food and service combinations to plot
food.sequence = seq(from = 0, to = 10, by = 1)
service.sequence = seq(from = 0, to = 10, by = 1)
df.to.plot <- expand.grid(food = food.sequence, service = service.sequence)

# for each food and service combination, compute a tip
# "by" is supposed to be better than a for loop
df.to.plot$tip <- by(df.to.plot, 1:nrow(df.to.plot), function(row) defuzzify(row))[]

# the plotting function that comes later requires a numeric matrix,
# so pivot by food and service and convert to a matrix
library(reshape2)
df <- dcast(df.to.plot, food ~ service, value.var = "tip")
df <- df[,-1] # get rid of the food column
row.names(df) <- food.sequence # name the rows
tip.matrix <- data.matrix(df)

# make a 3D interactive plot
library(plotly)
p <- plot_ly(z = tip.matrix) %>% add_surface() %>% 
  layout(title = "Tipping Plan",
         scene = list(
           xaxis = list(title = "Service (x)"),
           yaxis = list(title = "Food (y)"),
           zaxis = list(title = "Tip (z)")
         ) )

print(p)

## reset universe
sets_options("universe", NULL)