SI2020/RaportSzymonParafiński.md

6.8 KiB

Podprojekt indywidualny - Szymon Parafiński


W folderze Sklearn znajduje się wykorzystana baza, wygenerowane drzewo oraz reszta plików związana z podprojektem.

Wykorzystana metoda uczenia

Do realizacji podprojektu wykorzystano drzewa decyzyjne do decydowania, co należy zrobić po najechaniu na konkretne pole. Drzewo decyduje na jakim etapie jest roślina analizując poszczególne stany danego pola:

  • Dopiero co zasiana (kiełek)
    • 0: "Nie_podejmuj_działania"
  • Roślinka kiełkująca (młoda)
    • 1: "Zastosuj_nawóz"
  • Roślina starzejąca się, bez środka ochrony
    • 2: "Zastosuj_środek"
  • Roślinka dojrzałam gotowa do zbioru
    • 4: "Zbierz"
  • Roślina zepsuta, nie nadaje się do użytku
    • 5: "Roślina_już_zgniła-zbierz_i_wyrzuć".

Do implementacji drzew decyzyjnych w Pythonie wykorzystane zostały biblioteki sklearn , pandas,sys oraz pickle.

Uczenie modelu

loadLearningBase(): [python]

Metoda loadLearningBase rozpoczyna od utworzenia zbioru uczącego na podstawie tabeli zawierającej informacje wszystkich możliwych stanach roślinki.

  • col_names -> zawiera nagłówki poszczególnych kolumn
  • feature_cols -> zawiera nagłówki z kolumnami w których znajdują się dane do analizy
    col_names = ['Warzywo', 'Nawoz', 'Srodek', 'Stan', 'Dzialanie']
    base = pd.read_csv("Database.csv", header=None, names=col_names)
    feature_cols = ['Warzywo', 'Nawoz', 'Srodek', 'Stan']
    """ print dataset"""
    # print(base.head())

Tutaj dzielimy podane kolumny na dwa typy zmiennych:

  • zmienne docelowe ---> y
  • i zmienne funkcyjne ---> X

Aby móc sprawdzić wydajność modelu, dzielę zestaw danych na zestaw szkoleniowy i zestaw testowy ---> za pomocą funkcji train_test_split ().

    X = base[feature_cols]  # Features
    y = base.Dzialanie  # Target variable

    # Split dataset into training set and test set
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,
                                                        random_state=1)  # 70% training and 30% test

Wywołanie funkcji odpowiedzialnej za wygenerowanie drzewa.

    data = generateDecisionTree(X_train, X_test, y_train, y_test)

Dodatkowe elementy pozwalające na wizualizację stworzonego drzewa decyzyjnego poprzez wygenerowanie drzewa zależności if/else lub najpierw do pliku .dot, który następnie poddany odpowiedniej 'obróbce' utworzy obraz.

    """generate data for image"""
    # tree.export_graphviz(data, out_file='treeData.dot', filled=True, rounded=True, special_characters=True,
    #                      feature_names=feature_cols)

    """Printing if_styled tree to console"""
    # tree_to_code(data, feature_cols)

    return data

generateDecisionTree(): [python]

Metoda generateDecisionTree generuje drzewo decyzyjne na podstawie dostarczonej bazy danych.

Do zmiennej clf zapisujemy drzewo decyzyjne z biblioteki sklearn utworzone za pomocą metody DecisionTreeClassifier z parametrem criterion ustawionym na "entropy", który pozwala na uzyskiwanie informacji. Na drzewie wywołujemy metodę fit, która dopasowuje do drzewa zbiór uczący zadany w tablicach X_train i y_train. Po dopasowaniu danych możemy przewidzieć stan nowych przykładów, co robimy wywołując na drzewie metodę predict z parametrami, które zawierają informację o stanie danego pola.

def generateDecisionTree(X_train, X_test, y_train, y_test):
    # Create Decision Tree classifer object
    clf = DecisionTreeClassifier(criterion="entropy")

    # Train Decision Tree Classifer
    clf = clf.fit(X_train, y_train)

Aby ocenić dokładność naszego modelu przewidujemy odpowiedzi dla naszego zestawu testowego, aby móc go porównać z zestawem y_test i otrzymać dokładność wygenerowanego modelu.

	# Predict the response for test dataset
    y_pred = clf.predict(X_test)

    """Model Accuracy, how often is the classifier correct """
    # print("Accuracy:", metrics.accuracy_score(y_test, y_pred))

main(): [python]

Metoda main wywołuje pozostałe metody oraz zapisuje wygenerowany model do pliku .sav aby nie było trzeba ponownie generować drzewa, tylko wczytać już te wygenerowane.

generated = loadLearningBase()

    # Save generated tree
    filename = 'decisionTree.sav'
    pickle.dump(generated, open(filename, 'wb'))

Implementacja w projekcie całościowym

Klasa wywoływana w C++ nazywa się injectCode. Działanie polega na tym że, funkcja stanPola sprawdza jakie wartości ma dane pole i generuje odpowiednie polecenie do wykonania.

stanPola(): [C++]

void stanPola(int x, int y) {
	//[x][x][0] = 0 - brak chemii
	//[x][x][0] = 1 - tylko nawóz
	//[x][x][0] = 2 - tylko środek
	//[x][x][0] = 3 - środek i nawóz
	//[x][x][1] - wartość wzrostu rośliny 

	polecenie = "python pliki/injectCode.py 1 ";

	if (stan[x][y][0] == 0)
		polecenie.append("0 0 ");
	if (stan[x][y][0] == 1)
		polecenie.append("1 0 ");
	if (stan[x][y][0] == 2)
		polecenie.append("0 1 ");
	if (stan[x][y][0] == 3)
		polecenie.append("1 1 ");
	int w = (stan[x][y][1]);
	std::string s = std::to_string(w);
	polecenie.append(s);

	decisionTree(polecenie);
}

Następnie funckja decisionTree wykonuje wygenerowane zapytanie.

decisionTree(): [C++]

void decisionTree(string polecenie) {

	std::string str = polecenie;
	const char* c = str.c_str();
	system(c);

	int line = 0;
	ifstream inFile;
	inFile.open("pliki/dec.txt");
	if (!inFile) {
		cout << "Unable to open file";
		exit(1); // terminate with error
	}

	while (inFile >> line) {
		decyzja = line;
	}

	inFile.close();
	akcja();
}

injectCode(): [python]

import pickle
import sys


def prediction(warzywo, nawoz ,srodek, stan_wzrostu):
	filename = 'pliki/decisionTree.sav'
	tree = pickle.load(open(filename, 'rb'))
	val = (tree.predict([[warzywo, nawoz, srodek, stan_wzrostu]]))
	save(val)
    
def save(prediction):
	pred = str(prediction)
	plik = open('pliki/dec.txt', 'w')
	plik.write(pred[1])
	plik.close()

def decision(prediction):
	if prediction == 0:
		return "Nie_podejmuj_dzialania"
	elif prediction == 1:
		return "Zastosuj_nawoz"
	elif prediction == 2:
		return "Zastosuj_srodek"
	elif prediction == 4:
		return "Zbierz"
	elif prediction == 5:
		return "Roslina_juz_zgnila__zbierz_i_wyrzuc"



if __name__ == '__main__':
	# Map command line arguments to function arguments.
	prediction(*sys.argv[1:])

Generowane polecenie wygląda w ten sposób:

python injectCode.py a b c d

Gdzie:

  • a -> rodzaj warzywa
  • b -> czy roślina była nawożona
    • 0: "nie"
    • 1: "tak"
  • c -> czy na roślinie był stosowany środek ochronny
    • 0: "nie"
    • 1: "tak"
  • d -> stan wzrostu w jakim znajduje się roślina
    • [1,20) - kiełek,
    • [20,45) - młoda roślina,
    • [45,85) - dojrzała,
    • [80,100] - starzejąca się.