diff --git a/LabWork01/LabWork6/ConvertorDataFrame.py b/LabWork01/LabWork6/ConvertorDataFrame.py index ce0a029..6ffb1c7 100644 --- a/LabWork01/LabWork6/ConvertorDataFrame.py +++ b/LabWork01/LabWork6/ConvertorDataFrame.py @@ -2,7 +2,7 @@ import pandas as pd def covertorDataFrame(): - df = pd.read_csv("../../res/Stores.csv") + df = pd.read_csv("res/Stores.csv") # кол-во строчек для считывания countMainRows = 35 @@ -27,15 +27,13 @@ def covertorDataFrame(): 'Store_Sales': str } - mainDF = mainDF.astype(convert_dict) + newMainDF = mainDF.astype(convert_dict) # генеральная выборка - newDfGeneral = mainDF.iloc[0:25] + newDfGeneral = newMainDF.iloc[0:25] # выборка для проверки - newDfSupport = mainDF.iloc[25:35] - - print(newDfSupport[['TextStoreSales', 'TextStoreSales', 'TextStoreArea']]) + newDfSupport = newMainDF.iloc[25:35] return [newDfGeneral[['TextDailyCustomerCount', 'TextStoreArea', 'TextStoreSales']], newDfSupport[['TextDailyCustomerCount', 'TextStoreArea', 'TextStoreSales']]] diff --git a/LabWork01/LabWork6/ReservCopy/CopyTree.py b/LabWork01/LabWork6/ReservCopy/CopyTree.py new file mode 100644 index 0000000..0504c71 --- /dev/null +++ b/LabWork01/LabWork6/ReservCopy/CopyTree.py @@ -0,0 +1,117 @@ +import math +import pandas as pd +from functools import reduce + +from LabWork01.LabWork6.ConvertorDataFrame import covertorDataFrame + +# Дата сет +# data = [ +# ["красный", "квадрат", "красный квадрат"], +# ["красный", "прямоугольник", "красный прямоугольник"], +# ["красный", "круг", "красный круг"], +# ["красный", "треугольник", "красный треугольник"], +# +# ["зеленый", "квадрат", "зеленый квадрат"], +# ["зеленый", "треугольник", "зеленый треугольник"], +# ["зеленый", "круг", "зеленый круг"], +# ] +# df0 = pd.DataFrame(data) +# df0.columns = ["цвет", "форма", "результат"] + +df0 = covertorDataFrame()[0] + +# Лямбда-выражение для распределения значений, аргумент - pandas.Series, +# возвращаемое значение - массив с количеством каждого из значений +# Из вводных данных s с помощью value_counts() находим частоту каждого из значений, +# и пока в нашем словаре есть элементы, будет работать цикл, запускаемый items(). +# Чтобы выходные данные не менялись с каждым запуском цикла, мы используем sorted, +# который меняет порядок от большего к меньшему +# В итоге, генерируется массив, содержащий строку из следующих компонентов: ключ (k) и значение (v). +cstr = lambda s: [k + ":" + str(v) for k, v in sorted(s.value_counts().items())] + +# Структура данных Decision Tree +tree = { + # name: Название этого нода (узла) + "name": "decision tree " + df0.columns[-1] + " " + str(cstr(df0.iloc[:, -1])), + # df: Данные, связанные с этим нодом (узлом) + "df": df0, + # edges: Список ребер (ветвей), выходящих из этого узла, + # или пустой массив, если ниже нет листового узла. + "edges": [], +} + +# Генерацию дерева, у узлов которого могут быть ветви, сохраняем в open +open = [tree] + +# Лямба-выражение для вычесления энтропии. +# Аргумент - pandas.Series、возвращаемое значение - число энтропии +entropy = lambda s: -reduce(lambda x, y: x + y, map(lambda x: (x / len(s)) * math.log2(x / len(s)), s.value_counts())) + +# Зацикливаем, пока open не станет пустым +while (len(open) != 0): + # Вытаскиваем из массива open первый элемент, + # и вытаскиваем данные, хранящиеся в этом узле + n = open.pop(0) + df_n = n["df"] + + # В случае, если энтропия этого узла равна 0, мы больше не можем вырастить из него новые ветви + # поэтому прекращаем ветвление от этого узла + if 0 == entropy(df_n.iloc[:, -1]): + continue + # Создаем переменную, в которую будем сохранять список значений атрибута с возможностью разветвления + attrs = {} + # Исследуем все атрибуты, кроме последнего столбца класса атрибутов + for attr in df_n.columns[:-1]: + # Создаем переменную, которая хранит значение энтропии при ветвлении с этим атрибутом, + # данные после разветвления и значение атрибута, который разветвляется. + attrs[attr] = {"entropy": 0, "dfs": [], "values": []} + # Исследуем все возможные значения этого атрибута. + # Кроме того, sorted предназначен для предотвращения изменения порядка массива, + # из которого были удалены повторяющиеся значения атрибутов, при каждом его выполнении. + for value in sorted(set(df_n[attr])): + # Фильтруем данные по значению атрибута + df_m = df_n.query(attr + "=='" + value + "'") + # Высчитываем энтропию, данные и значения сохрнаяем + attrs[attr]["entropy"] += entropy(df_m.iloc[:, -1]) * df_m.shape[0] / df_n.shape[0] + attrs[attr]["dfs"] += [df_m] + attrs[attr]["values"] += [value] + pass + pass + # Если не осталось ни одного атрибута, значение которого можно разделить, + # прерываем исследование этого узла. + if len(attrs) == 0: + continue + # Получаем атрибут с наименьшим значением энтропии + attr = min(attrs, key=lambda x: attrs[x]["entropy"]) + # Добавляем каждое значение разветвленного атрибута + # и данные, полученные после разветвления, в наше дерево и в open. + for d, v in zip(attrs[attr]["dfs"], attrs[attr]["values"]): + m = {"name": attr + "=" + v, "edges": [], "df": d.drop(columns=attr)} + n["edges"].append(m) + open.append(m) + pass + +# Выводим дата сет +print(df0, "\n-------------") + + +# Метод преобразования дерева в символы, аргуметы - tree:структура данных древа, +# indent:присоединяймый к дочернему узлу indent, +# Возвращаемое значение - символьное представление древа. +# Этот метод вызывается рекурсивно для преобразования всех данных в дереве в символы. +def tstr(tree, indent=""): + # Создаем символьное представление этого узла. + # Если этот узел является листовым узлом (количество элементов в массиве ребер равно 0), + # частотное распределение последнего столбца данных df, связанных с деревом, преобразуется в символы. + s = indent + tree["name"] + str(cstr(tree["df"].iloc[:, -1]) if len(tree["edges"]) == 0 else "") + "\n" + # Зацикливаем все ветви этого узла. + for e in tree["edges"]: + # Добавляем символьное представление дочернего узла к символьному представлению родительского узла. + # Добавляем еще больше символов к indent этого узла. + s += tstr(e, indent + " ") + pass + return s + + +# Выводим древо в его символьном представлении. +print(tstr(tree)) diff --git a/LabWork01/LabWork6/Tree.py b/LabWork01/LabWork6/Tree.py index 0504c71..0b749af 100644 --- a/LabWork01/LabWork6/Tree.py +++ b/LabWork01/LabWork6/Tree.py @@ -1,32 +1,11 @@ import math -import pandas as pd from functools import reduce from LabWork01.LabWork6.ConvertorDataFrame import covertorDataFrame -# Дата сет -# data = [ -# ["красный", "квадрат", "красный квадрат"], -# ["красный", "прямоугольник", "красный прямоугольник"], -# ["красный", "круг", "красный круг"], -# ["красный", "треугольник", "красный треугольник"], -# -# ["зеленый", "квадрат", "зеленый квадрат"], -# ["зеленый", "треугольник", "зеленый треугольник"], -# ["зеленый", "круг", "зеленый круг"], -# ] -# df0 = pd.DataFrame(data) -# df0.columns = ["цвет", "форма", "результат"] - +# дата-сет df0 = covertorDataFrame()[0] -# Лямбда-выражение для распределения значений, аргумент - pandas.Series, -# возвращаемое значение - массив с количеством каждого из значений -# Из вводных данных s с помощью value_counts() находим частоту каждого из значений, -# и пока в нашем словаре есть элементы, будет работать цикл, запускаемый items(). -# Чтобы выходные данные не менялись с каждым запуском цикла, мы используем sorted, -# который меняет порядок от большего к меньшему -# В итоге, генерируется массив, содержащий строку из следующих компонентов: ключ (k) и значение (v). cstr = lambda s: [k + ":" + str(v) for k, v in sorted(s.value_counts().items())] # Структура данных Decision Tree @@ -35,8 +14,7 @@ tree = { "name": "decision tree " + df0.columns[-1] + " " + str(cstr(df0.iloc[:, -1])), # df: Данные, связанные с этим нодом (узлом) "df": df0, - # edges: Список ребер (ветвей), выходящих из этого узла, - # или пустой массив, если ниже нет листового узла. + # edges: Список ребер (ветвей), выходящих из этого узла, или пустой массив, если ниже нет листового узла. "edges": [], } @@ -49,42 +27,33 @@ entropy = lambda s: -reduce(lambda x, y: x + y, map(lambda x: (x / len(s)) * mat # Зацикливаем, пока open не станет пустым while (len(open) != 0): - # Вытаскиваем из массива open первый элемент, - # и вытаскиваем данные, хранящиеся в этом узле + n = open.pop(0) df_n = n["df"] - # В случае, если энтропия этого узла равна 0, мы больше не можем вырастить из него новые ветви - # поэтому прекращаем ветвление от этого узла if 0 == entropy(df_n.iloc[:, -1]): continue - # Создаем переменную, в которую будем сохранять список значений атрибута с возможностью разветвления + attrs = {} - # Исследуем все атрибуты, кроме последнего столбца класса атрибутов + for attr in df_n.columns[:-1]: - # Создаем переменную, которая хранит значение энтропии при ветвлении с этим атрибутом, - # данные после разветвления и значение атрибута, который разветвляется. + attrs[attr] = {"entropy": 0, "dfs": [], "values": []} - # Исследуем все возможные значения этого атрибута. - # Кроме того, sorted предназначен для предотвращения изменения порядка массива, - # из которого были удалены повторяющиеся значения атрибутов, при каждом его выполнении. + for value in sorted(set(df_n[attr])): - # Фильтруем данные по значению атрибута df_m = df_n.query(attr + "=='" + value + "'") - # Высчитываем энтропию, данные и значения сохрнаяем + attrs[attr]["entropy"] += entropy(df_m.iloc[:, -1]) * df_m.shape[0] / df_n.shape[0] attrs[attr]["dfs"] += [df_m] attrs[attr]["values"] += [value] pass pass - # Если не осталось ни одного атрибута, значение которого можно разделить, - # прерываем исследование этого узла. + if len(attrs) == 0: continue - # Получаем атрибут с наименьшим значением энтропии + attr = min(attrs, key=lambda x: attrs[x]["entropy"]) - # Добавляем каждое значение разветвленного атрибута - # и данные, полученные после разветвления, в наше дерево и в open. + for d, v in zip(attrs[attr]["dfs"], attrs[attr]["values"]): m = {"name": attr + "=" + v, "edges": [], "df": d.drop(columns=attr)} n["edges"].append(m) @@ -94,24 +63,16 @@ while (len(open) != 0): # Выводим дата сет print(df0, "\n-------------") - -# Метод преобразования дерева в символы, аргуметы - tree:структура данных древа, -# indent:присоединяймый к дочернему узлу indent, -# Возвращаемое значение - символьное представление древа. -# Этот метод вызывается рекурсивно для преобразования всех данных в дереве в символы. def tstr(tree, indent=""): - # Создаем символьное представление этого узла. - # Если этот узел является листовым узлом (количество элементов в массиве ребер равно 0), - # частотное распределение последнего столбца данных df, связанных с деревом, преобразуется в символы. s = indent + tree["name"] + str(cstr(tree["df"].iloc[:, -1]) if len(tree["edges"]) == 0 else "") + "\n" # Зацикливаем все ветви этого узла. for e in tree["edges"]: - # Добавляем символьное представление дочернего узла к символьному представлению родительского узла. - # Добавляем еще больше символов к indent этого узла. s += tstr(e, indent + " ") pass return s +def getStringTree(): + return tstr(tree) # Выводим древо в его символьном представлении. print(tstr(tree)) diff --git a/LabWork01/LoadDB.py b/LabWork01/LoadDB.py index da8b867..1457cd6 100644 --- a/LabWork01/LoadDB.py +++ b/LabWork01/LoadDB.py @@ -1,6 +1,6 @@ import os import secrets -from flask import Flask, redirect, url_for, request, render_template, session +from flask import Flask, request, render_template, session from matplotlib import pyplot as plt from LabWork01.AnalysCustomers import analysCustomersDataFrame @@ -15,6 +15,7 @@ from LabWork01.LabWork3.DeletePng import deleteAllPng from LabWork01.LabWork4.SiteSearch import SiteSearch from LabWork01.LabWork5.create_plot import create_plot_jpg from LabWork01.LabWork6.ConvertorDataFrame import covertorDataFrame +from LabWork01.LabWork6.Tree import getStringTree app = Flask(__name__) @@ -45,9 +46,8 @@ search_engine.add("https://www.kaggle.com/datasets/surajjha101/forbes-billionair search_engine.add("https://www.kaggle.com/datasets/fedesoriano/stroke-prediction-dataset", [ "heart_disease" , "bmi", "stroke" ]) -@app.route("/") +@app.route("/", methods=['GET','POST']) def home(): - covertorDataFrame(listShops) return render_template('main_page.html', context=[], main_img=[], messages=[], image_names=[], tableAnalys=[], titles=[''], listTypes=listTypes, countNull=countNull, firstRow=1, secondRow=4, firstColumn=1, secondColumn=4) @app.route("/showDiapason", methods=['GET','POST']) @@ -214,6 +214,12 @@ def get_plot_image(): listTypes=listTypes, countNull=countNull, firstRow=1, secondRow=4, firstColumn=1, secondColumn=4) +@app.route('/createTree', methods=['GET']) +def get_data_Tree(): + DataTree = getStringTree() + + return render_template('tree_page.html', DataTree=DataTree) + if __name__=="__main__": app.run(debug=True) diff --git a/LabWork01/templates/main_page.html b/LabWork01/templates/main_page.html index 77a76b5..f16f1c3 100644 --- a/LabWork01/templates/main_page.html +++ b/LabWork01/templates/main_page.html @@ -31,6 +31,11 @@ +