DSZI_2020_Projekt/polecanie_dań_Natalia_Plitta.md
2020-05-24 20:38:43 +02:00

6.5 KiB

Raport przygotowała: Natalia Plitta
Raportowany okres: 11 maja - 25 maja 2020
Niniejszy raport poświęcony jest przekazaniu informacji na temat stanu mini-projektu indywidualnego w ramach projektu grupowego realizowanego na przedmiot Sztuczna Inteligencja w roku akademickim 2019/2020.

Tematem realizowanego projektu indywidualnego jest stworzenie sztucznej inteligencji, która na podstawie podanych parametrów poleca jedno z siedmiu dań. Wykorzystane zostały poniższe biblioteki:

  • scikit - learn
  • joblib
  • IPython
  • pandas
  • pydotplus
  • StringIO

Realizacja projektu

Import danych:

Na początku dane są pobierane z pliku "Nowy.csv" gdzie zostały przygotowane 121 wiersze o kolumnach z kolejno podanymi nazwami. Następnie model zostal podzielony na cechy i etykietę ['number'], która oznacza polecane danie.

    col_names = ['age', 'sex', 'fat', 'fiber', 'spicy', 'number']
    model_tree = pd.read_csv("Nowy.csv", header=None, names=col_names)
    model_tree.head()
    feature_cols = ['age', 'sex', 'fat', 'fiber', 'spicy']
    X = model_tree[feature_cols]
    y = model_tree.number

Dane:

Aby utworzyć model stworzyłam 121 wierszy z 6 kolejnych liczb oznaczających:

  • wiek klienta (7 - 80);
  • zawartość tłuszczu w daniu (0 - 16);
  • zawartość błonnika w daniu (0 - 16);
  • płeć osoby zamawiającej (0 - kobieta lub 1 - mężczyzna);
  • ostrość dania (0 - 5);
  • polecane danie o danym numerze:
    1. zupa z soczewicy
    2. frytki pieczone
    3. makaron z sosem brokułowym
    4. pikantne skrzydełka zasmażane
    5. ostre zasmażane tofu
    6. hiszpańska zapiekanka ziemniaczana
    7. pieczone warzywa

Poszczególne liczby są oddzielone przecinkami, a wiersze znakiem nowej linii, plik z rozszerzeniem .csv.

Drzewa decyzyjne:

Następnie następuje podział danych na zestaw treningowy i testowy. Zestaw treningowy to 70% danych, testowy 30%. X to zestaw cech, Y zestaw wyników - tutaj etykieta "number".

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,
                                                        random_state=1)

Do stworzenia modelu drzew została wykorzystana funkcja DecisionTreeClassifier. Pierwsze drzewo przyjmuje jako kryterium indeks Gini (domyślny), drugie drzewo entropię.

   clf = DecisionTreeClassifier()
   clf = DecisionTreeClassifier(criterion="entropy")

Do modelu drzewa zostały wczytane dane, dzięki funkcji fit.

   clf = clf.fit(X_train, y_train)

Generowane przewidywania są agregowane w zmiennej y_pred, dzięki funckji predict.

   y_pred = clf.predict(X_test)

Następnie wyświetlana jest akuratność dla modelu danych o wybranym kryterium, dzięki funkcji accuracy_score.

print("Accuracy:", metrics.accuracy_score(y_test, y_pred))

Drzewo decyzyjne ma swoją reprezentację graficzną, która utworzona została dzięki bibliotece IPython, graphviz, StringIO.

    dot_data = StringIO()
    export_graphviz(clf, out_file=dot_data,
                    filled=True, rounded=True,
                    special_characters=True, feature_names=feature_cols,
                    class_names=['1', '2', '3', '4', '5', '6', '7'])
    graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
    graph.write_png('polecanie_1.png')
    Image(graph.create_png())

Na końcu model (z większym wskaźnikiem trafności) zostaje zapisany do pliku z rozszerzeniem sav.

    file_name = 'final_model.sav'
    joblib.dump(clf, file_name)

Integracja z projektem

Po uruchomieniu programu, należy nacisnąć na przycisk Polecanie dań, a wtedy uruchomiona zostaje funkcja Tree_natalia(), która ładuje z pliku model drzewa. Zainicjowany zostaje również przykładowy stan restauracji (dodanie kilku klientów, przypisanie im stołów i talerzy). Wywoływany jest też przykładowy ruch kelnera, który podchodzi do kilku stolików i pomaga w doborze dania.

def Tree_natalia(d):
    if d == 1:
        loaded_model = joblib.load('Natalia/final_model.sav')
        messagebox.showinfo("Zaczynamy!", "Zaczynamy!")

        prefer1 = Dish("prefer1", 40, 20, 15)
        prefer2 = Dish("prefer2", 25, 10, 10)
        prefer3 = Dish("prefer3", 55, 25, 28)

        plate1 = Plate(prefer1, "Natalia/danie1.png")
        plate2 = Plate(prefer2, "Natalia/danie2.png")
        plate3 = Plate(prefer3, "Natalia/danie3.png")

        client1 = Client(25, 1, 45, 1)
        client2 = Client(41, 0, 22, 4)
        client3 = Client(10, 0, 32, 8)

        client1.takePlateAndEat(plate1)
        client2.takePlateAndEat(plate2)
        client3.takePlateAndEat(plate3)

        bot.goByAStar((tables[1].pos[0] + 1, tables[1].pos[1]))
        opinion = show_predict(prefer1, client1, loaded_model)

        bot.goByAStar((tables[3].pos[0] + 1, tables[3].pos[1]))
        opinion = show_predict(prefer2, client2, loaded_model)

        bot.goByAStar((tables[5].pos[0] + 1, tables[5].pos[1]))
        opinion = show_predict(prefer3, client3, loaded_model)

Następnie przy pomocy funkcji show_predict() wyświetlane jest zdjęcie poleconego dania. Funkcja jako parametry przyjmuje obiekty danie, klient i załadowany model.

def show_predict(dish, client, model):
    data = []
    data.append(client.age)
    data.append(dish.fatContent)
    data.append(dish.fiberContent)
    data.append(client.sex)
    data.append(dish.spicy)
    prediction = model.predict([data])


    if prediction == 1:
        ShowImg("Natalia/danie1.png")
        return prediction
    elif prediction == 2:
        ShowImg("Natalia/danie2.png")
        return prediction
    elif prediction == 3:
        ShowImg("Natalia/danie3.png")
        return prediction
    elif prediction == 4:
        ShowImg("Natalia/danie4.png")
        return prediction
    elif prediction == 5:
        ShowImg("Natalia/danie5.png")
        return prediction
    elif prediction == 6:
        ShowImg("Natalia/danie6.png")
        return prediction
    else:
        ShowImg("Natalia/danie7.png")
        return prediction

Pola fatContent, fiberContent, spicy klasy Dish w momencie tworzenia instancji klasy są ustawiane na losowo wygenerowaną liczbę z odpowiednich przedziałów:

self.fatContent = random.randint(0, 16)
self.fiberContent = random.randint(0, 16)
self.spicy = random.randint(0, 5)

Po zakończeniu trasy wyświetlany jest stosowny komunikat, a aplikacja zostaje wyłączona.