fuzzy-game-recommender/fuzzy_controllers.py
2023-02-01 16:15:56 +01:00

137 lines
6.3 KiB
Python

import simpful as sf
import numpy as np
import matplotlib.pylab as plt
# Fix for the "detected Sugeno model type" spam - overwrite the annoying method from simpful
class FuzzySystem(sf.FuzzySystem):
def _set_model_type(self, model_type):
if self._detected_type == "inconsistent": return
if self._detected_type is None:
self._detected_type = model_type
# Just commenting the line below!
#print(" * Detected %s model type" % model_type)
elif self._detected_type != model_type:
print("WARNING: model type is unclear (simpful detected %s, but a %s output was specified)" % (
self._detected_type, model_type))
self._detected_type = 'inconsistent'
def fuzzy_controler_popularity(price: float, game_length: int, rating: float, number_of_owners: int) -> float:
FS = FuzzySystem(show_banner=False)
S_1 = sf.FuzzySet(points=[[0., 1.], [30., 0.]], term="negative")
S_2 = sf.FuzzySet(points=[[35., 0.], [40., 1.], [60., 1.], [70., 0.]], term="average")
S_3 = sf.FuzzySet(points=[[80., 0.], [90., 1.]], term="positive")
FS.add_linguistic_variable("Rating", sf.LinguisticVariable([S_1, S_2, S_3], concept="Rating"))
S_1 = sf.FuzzySet(points=[[0., 1.], [50000., 0.]], term="small")
S_2 = sf.FuzzySet(points=[[100000., 0.], [300000., 1.], [3000000., 1.], [5000000., 0.]], term="average")
S_3 = sf.FuzzySet(points=[[10000000., 0.], [30000000., 1.]], term="big")
FS.add_linguistic_variable("Number_of_owners",
sf.LinguisticVariable([S_1, S_2, S_3], concept="Number_of_owners"))
S_1 = sf.FuzzySet(points=[[0., 1.], [10., 0.]], term="cheap")
S_2 = sf.FuzzySet(points=[[10., 0.], [15., 1.], [20., 1.], [25., 0.]], term="average")
S_3 = sf.FuzzySet(points=[[25., 0.], [35., 1.]], term="expensive")
FS.add_linguistic_variable("Price", sf.LinguisticVariable([S_1, S_2, S_3], concept="Price"))
F_1 = sf.FuzzySet(points=[[200., 1.], [300., 0.]], term="short")
F_2 = sf.FuzzySet(points=[[300., 0.], [360., 1.], [420., 1.], [500., 0.]], term="average")
F_3 = sf.FuzzySet(points=[[500., 0.], [550., 1.]], term="long")
FS.add_linguistic_variable("Game_length", sf.LinguisticVariable([F_1, F_2, F_3], concept="Game_length"))
FS.set_crisp_output_value("small", 0)
FS.set_crisp_output_value("average", 0.5)
FS.set_crisp_output_value("big", 1)
R1 = "IF (Price IS average) OR (Game_length IS average) OR (Rating IS average) OR (Number_of_owners IS average) " \
"THEN (Popularity IS average)"
R2 = "IF (Price IS expensive) AND (Game_length IS long) AND (Rating IS positive) THEN (Popularity IS big)"
R3 = "IF (Price IS expensive) AND (Game_length IS short) THEN (Popularity IS small)"
R4 = "IF (Price IS cheap) THEN (Popularity IS big)"
R5 = "IF (Rating IS negative) THEN (Popularity IS small)"
R6 = "IF (Rating IS positive) AND (Number_of_owners IS small) THEN (Popularity IS average)"
R7 = "IF (Rating IS average) AND (Price IS cheap) THEN (Popularity IS big)"
FS.add_rules([R1, R2, R3, R4, R5, R6, R7])
FS.set_variable("Price", price)
FS.set_variable("Game_length", game_length)
FS.set_variable("Rating", rating)
FS.set_variable("Number_of_owners", number_of_owners)
popularity = FS.Sugeno_inference(["Popularity"], ignore_warnings=True)
return round(popularity["Popularity"], 2)
def fuzzy_controler_similiarity(categorical_data: str, numerical_data: str, vector_distance: float, show_graph: bool)\
-> float:
FSS = FuzzySystem(show_banner=False)
S_1 = sf.FuzzySet(points=[[.20, 1.], [.30, 0.]], term="small")
S_2 = sf.FuzzySet(points=[[.30, 0.], [.55, 1.], [.65, 1.], [.85, 0.]], term="average")
S_3 = sf.FuzzySet(points=[[.85, 0.], [.90, 1.]], term="big")
FSS.add_linguistic_variable("Categorical_similarity",
sf.LinguisticVariable([S_1, S_2, S_3], concept="Categorical similarity"))
S_1 = sf.FuzzySet(points=[[.30, 1.], [.40, 0.]], term="small")
S_2 = sf.FuzzySet(points=[[.40, 0.], [.50, 1.], [.60, 1.], [.70, 0.]], term="average")
S_3 = sf.FuzzySet(points=[[.70, 0.], [.90, 1.]], term="big")
FSS.add_linguistic_variable("Numerical_difference",
sf.LinguisticVariable([S_1, S_2, S_3], concept="Numerical difference"))
S_1 = sf.FuzzySet(points=[[.20, 1.], [.30, 0.]], term="small")
S_2 = sf.FuzzySet(points=[[.30, 0.], [.55, 1.], [.65, 1.], [.85, 0.]], term="average")
S_3 = sf.FuzzySet(points=[[.85, 0.], [.90, 1.]], term="big")
FSS.add_linguistic_variable("Word_vector_distance",
sf.LinguisticVariable([S_1, S_2, S_3], concept="Word vector distance"))
FSS.set_crisp_output_value("small", 0)
FSS.set_crisp_output_value("average", 0.5)
FSS.set_crisp_output_value("big", 1)
# TODO: add Word_vector_distance to rules
R1 = "IF (Categorical_similarity IS average) AND (Numerical_difference IS average) THEN (Similarity IS average)"
R2 = "IF (Categorical_similarity IS small) AND (Numerical_difference IS big) THEN (Similarity IS small)"
R3 = "IF (Categorical_similarity IS big) AND (Numerical_difference IS small) THEN (Similarity IS big)"
FSS.add_rules([R1, R2, R3])
# show graph for two variables
if show_graph:
plot_graphs(FS=FSS)
FSS.set_variable("Categorical_similarity", vector_distance)
FSS.set_variable("Numerical_difference", numerical_data)
popularity = FSS.Sugeno_inference(["Similarity"], ignore_warnings=True)
return round(popularity["Similarity"], 2)
def plot_graphs(FS: sf.FuzzySystem):
xs = []
ys = []
zs = []
for x in np.linspace(0, 1):
for y in np.linspace(0, 1):
FS.set_variable("Categorical_similarity", x)
FS.set_variable("Numerical_difference", y)
tip = FS.inference()['Similarity']
xs.append(x)
ys.append(y)
zs.append(tip)
xs = np.array(xs)
ys = np.array(ys)
zs = np.array(zs)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
xx, yy = plt.meshgrid(xs, ys)
ax.plot_trisurf(xs, ys, zs, vmin=0, vmax=100)
ax.set_xlabel("Categorical_similarity")
ax.set_ylabel("Numerical_difference")
ax.set_zlabel("Similarity")
ax.set_zlim(0, 1)
plt.tight_layout()
plt.show()