392 KiB
Приступаем к работе...¶
import numpy as np
import skfuzzy as fuzz
import matplotlib.pyplot as plt
import pandas as pd
df_house = pd.read_csv(".//static//csv//kc_house_data.csv")
df_house.columns
df_house.head()
df_house.describe()
# Процент пропущенных значений признаков
for i in df_house.columns:
null_rate = df_house[i].isnull().sum() / len(df_house) * 100
if null_rate > 0:
print(f'{i} Процент пустых значений: %{null_rate:.2f}')
print(df_house.isnull().sum())
print(df_house.isnull().any())
# Проверка типов столбцов
df_house.dtypes
Определим входные и выходные переменные (данные)¶
Перед построением нечёткой системы, нужно определить, какие переменные будут входными, а какие - выходными.
Входные переменные (fuzzy inputs)
Входные X: bathrooms - ванные, sqft_living - площадь
Выходные переменные (fuzzy output)
Выходные Y: price - цены.
Настройка лингвистических переменных¶
Заключается в определении термов, которые будут соответствовать переменным, ну и их тип. (Какие-то будут функциями принадлежности, другие треугольными).
Всем параметрам присваиваются значения low, medium, high
Создадим лингвистические переменные
from skfuzzy import control as ctrl
# Определим входные и выходные переменные
sqft_living = ctrl.Antecedent(df_house['sqft_living'].sort_values(), "sqft_living")
bathrooms = ctrl.Antecedent(df_house['bathrooms'].sort_values(), "bathrooms")
price = ctrl.Consequent(df_house['price'].sort_values(), "price")
Формирование нечётких переменных для лингвистических переменных¶
Определение функций принадлежности
sqft_living['low'] = fuzz.zmf(sqft_living.universe, 0, 5000)
sqft_living['medium'] = fuzz.trapmf(sqft_living.universe, [3400, 5700, 7800, 9900])
sqft_living['high'] = fuzz.trimf(sqft_living.universe, [8000, 13580, 13580])
sqft_living.view()
bathrooms['low'] = fuzz.zmf(bathrooms.universe, 0, 3)
bathrooms['medium'] = fuzz.trapmf(bathrooms.universe, [1, 3, 4, 6])
bathrooms['high'] = fuzz.trimf(bathrooms.universe, [5, 8, 8])
bathrooms.view()
#price['low'] = fuzz.zmf(price.universe, 0, 2500000)
#price['medium'] = fuzz.trapmf(price.universe, [1500000, 3000000, 4000000, 5500000])
#price['high'] = fuzz.trimf(price.universe, [4000000, 9000000, 11000000])
# Для более точного определения цены
price.automf(5, variable_type="quant")
price.view()
Формирование и визуализация базы нечётких правил¶
Определение правил: установим логические зависимости между входными и выходными переменными.
Правила:
1. Если количество ванн маленькое и площадь маленькая, то цена очень дешёвая
2. Если количество ванн маленькое и площадь средняя, то цена дешёвая
3. Если количество ванн маленькое и площадь большая, то цена средняя
4. Если количество ванн среднее и площадь маленькая, то цена очень дешёвая
5. Если количество ванн среднее и площадь средняя, то цена средняя
6. Если количество ванн среднее и площадь большая, то цена высокая
7. Если количество ванн большое и площадь маленькая, то цена дешёвая
8. Если количество ванн большое и площадь средняя, то цена высокая
9. Если количество ванн большое и площадь большая, то цена очень высокая
В случае ошибки необходимо в файле
.venv/lib/python3.13/site-packages/skfuzzy/control/visualization.py
удалить лишний отступ на 182 строке, должно быть:
if not matplotlib_present:
raise ImportError("ControlSystemVisualizer
can only be used "
"with matplotlib
present in the system.")
self.ctrl = control_system
self.fig, self.ax = plt.subplots()
После этого обязательно перезапустить ядро!
# Для сформированных нечётких переменных поработаем с нечёткими правилами (bathrooms, sqft_living, price)
rule1 = ctrl.Rule(bathrooms['low'] & sqft_living['low'], price['lower'])
rule2 = ctrl.Rule(bathrooms['low'] & sqft_living['medium'], price['low'])
rule3 = ctrl.Rule(bathrooms['low'] & sqft_living['high'], price['average'])
rule4 = ctrl.Rule(bathrooms['medium'] & sqft_living['low'], price['lower'])
rule5 = ctrl.Rule(bathrooms['medium'] & sqft_living['medium'], price['average'])
rule6 = ctrl.Rule(bathrooms['medium'] & sqft_living['high'], price['high'])
rule7 = ctrl.Rule(bathrooms['high'] & sqft_living['low'], price['average'])
rule8 = ctrl.Rule(bathrooms['high'] & sqft_living['medium'], price['high'])
rule9 = ctrl.Rule(bathrooms['high'] & sqft_living['high'], price['higher'])
rule1.view()
Создание нечёткой системы и добавление нечётких правил в базу знаний нечёткой системы¶
price_ctrl = ctrl.ControlSystem(
[
rule1,
rule2,
rule3,
rule4,
rule5,
rule6,
rule7,
rule8,
rule9,
]
)
prices = ctrl.ControlSystemSimulation(price_ctrl)
price_ctrl.view()
Пример расчёта выходной переменной price на основе входных переменных¶
prices.input['bathrooms'] = 1
prices.input['sqft_living'] = 3420
prices.compute()
prices.print_state()
print(prices.output['price'])
Визуализация функции принадлежности для выходной переменной price¶
Функция получена в процессе аккумуляции и используется для дефаззификации значения выходной переменной price
price.view(sim=prices)
Тестирование нечёткой системы¶
# Функция для автоматизации вычисления целевой переменной Y на основе вектора признаков X
def fuzzy_pred(row):
prices.input['bathrooms'] = row['bathrooms']
prices.input['sqft_living'] = row['sqft_living']
prices.compute()
return prices.output['price']
res = df_house[['bathrooms', 'sqft_living', 'price']].head(100)
res['Pred'] = res.apply(fuzzy_pred, axis=1)
res.head(15)
Успешно выполнилось заполнение данными и предсказание
Оценка результатов на основе метрик для задачи регрессии¶
import math
from sklearn import metrics
rmetrics = {}
rmetrics["RMSE"] = math.sqrt(metrics.mean_squared_error(res['price'], res['Pred']))
rmetrics["RMAE"] = math.sqrt(metrics.mean_absolute_error(res['price'], res['Pred']))
rmetrics["R2"] = metrics.r2_score(res['price'], res['Pred'])
rmetrics
Визуализация оценки качества нечёткой системы и проверка системы¶
Тестирование работы модели, проводилось также. После того, как подали тестовые данные, система определила цену.
# Берём случайно записи из фрейма
df_random = df_house[['bathrooms', 'sqft_living', 'price']].sample(20, random_state=42)
df_random = df_random.reset_index(drop=True)
predicted_prices = []
for i in range(len(df_random)):
prices.input['bathrooms'] = df_random.loc[i, 'bathrooms']
prices.input['sqft_living'] = df_random.loc[i, 'sqft_living']
prices.compute()
# a = prices.print_state()
predicted_prices.append(prices.output['price'])
df_random['Predicted Price'] = predicted_prices
df_random_sorted = df_random.sort_values(by='price')
# Вывод результатов
print(df_random_sorted[['bathrooms', 'sqft_living', 'price', 'Predicted Price']])
# Визуализация графиком
plt.figure(figsize=(10, 5))
plt.plot(df_random.index, df_random_sorted['price'], marker='o', label='Real Price', color='red')
plt.plot(df_random.index, df_random_sorted['Predicted Price'], marker='s', label='Predicted Price', color='green')
plt.xlabel("Index")
plt.ylabel("Price")
plt.legend()
plt.title("Сравнение реальных цен с предсказанными")
plt.show()
Вывод... Стало более лучше. Результаты предсказанных цен стали точнее, а некоторые цены почти совпали.
Система лучше предсказывает цену, по входным характеристикам. По крайней мере предсказание стало лучше предыдущего.
Как-то так ^_^