This content is powered by Balige Publishing. Visit this link (collaboration with Rismon Hasiholan Sianipar)
In this tutorial, you will learn how to use Pandas, NumPy and other libraries to perform simple classification using perceptron and Adaline (adaptive linear neuron). The dataset used is Iris dataset directly from the UCI Machine Learning Repository.
Step 1: Open Qt Designer. Create the form using the Main Window template, as shown in Figure below.
Step 2: Click the Create button. Then, place a Push Button widget on the form. Specify the text property of the Push Button widget in the Property Editor window to Load Data. Then, set the property of the objectName of the Push Button widget in the Property Editor window to pbLoad.
Step 3: Place a Widget from the Containers panel on the form. Set the objectName property to widgetData.
Step 4: Save the form as gui_perceptron.ui. Now, the form looks as shown in Figure below.
Step 5: Next, right-click on the Widget and from the context menu displayed select Promote to .... Set the Promoted class name as graphics_perceptron as shown in Figure below.
Step 7: Define the graphics_perceptron class (according to the class name from widgetData) in a Python file. Save it as graphics_perceptron.py as follows:
Step 8: Create a new class, Perceptron, save it as Perceptron_Class.py as follows:
Step 9: Define the new Python script, Perceptron.py, defines the method display_data() and connect it with the clicked() event from pbData widget as follows:
Step 10: Run Perceptron.py script and click the Load Data button. The scatter plot of extracted data will be displayed as shown in Figure below.
Step 11: On gui_perceptron.ui form, add a Spin Box widget and set its minimum, maximum, singleStep, and value properties to 10, 100, 2, and 100. Set its objectName property to sbLength.
Step 12: Then, add a Table Widget onto form and set its objectName property as tableData. Now the form looks as shown in Figure below.
Step 13: Modify load_data() and display_data() functions so that the length of data extracted is determined by value property of sbLength widget as follows:
Step 14: Connect valueChanged() signal of sbLength with display_data() function and add it inside __init__() function:
Step 15: Define write_df_to_qtable() and display_table() functions to read data frame and display it on table widget.
Step 16: Invoke display_table() from load_data() function as shown in line 14:
Step 17: Run Perceptron.py to see the scatter plot of extracted data and its representation of table as shown in Figure below.
Step 18: Next, add two Widgets onto form and set their objectName properties as widgetDecision and widgetEpoch. Now, the form looks as shown in Figure below.
Step 19: Promote widgetDecision and widgetEpoch to graphics_perceptron class by doing as shown in Step 5 and Step 6.
Step 20: Define display_epoch() and display_decision() functions to display both error in every epoch (iteration) in widgetEpoch and the decision regions in widgetDecision as follows:
Step 21: Invoke display_epoch() and display_decision() functions in load_data() as shown in line:
Step 22: Run Perceptron.py and click on Load Data button. You will see error in every iteration graph and decision regions as shown in Figure below.
Step 23: Change data length and you will get the result as shown in Figure below.
In this tutorial, you will learn how to use Pandas, NumPy and other libraries to perform simple classification using perceptron and Adaline (adaptive linear neuron). The dataset used is Iris dataset directly from the UCI Machine Learning Repository.
Step 1: Open Qt Designer. Create the form using the Main Window template, as shown in Figure below.
Step 2: Click the Create button. Then, place a Push Button widget on the form. Specify the text property of the Push Button widget in the Property Editor window to Load Data. Then, set the property of the objectName of the Push Button widget in the Property Editor window to pbLoad.
Step 3: Place a Widget from the Containers panel on the form. Set the objectName property to widgetData.
Step 4: Save the form as gui_perceptron.ui. Now, the form looks as shown in Figure below.
Step 5: Next, right-click on the Widget and from the context menu displayed select Promote to .... Set the Promoted class name as graphics_perceptron as shown in Figure below.
Step 6: Then, click the Add button and click the Promote button. In the Object Inspector window, you can see that widgetData (graphics_perceptron class) along with the pbLoad object (QPushButton class) are now in the centralwidget object (QWidget class) as shown in Figure below.
#graphics_perceptron.py from PyQt5.QtWidgets import* from matplotlib.backends.backend_qt5agg import FigureCanvas from matplotlib.figure import Figure class graphics_perceptron(QWidget): def __init__(self, parent = None): QWidget.__init__(self, parent) self.canvas = FigureCanvas(Figure()) vertical_layout = QVBoxLayout() vertical_layout.addWidget(self.canvas) self.canvas.axis1 = self.canvas.figure.add_subplot(111) self.canvas.figure.set_facecolor("xkcd:beige") self.setLayout(vertical_layout)
Step 8: Create a new class, Perceptron, save it as Perceptron_Class.py as follows:
#Perceptron_Class.py import numpy as np class Perceptron(object): """Perceptron classifier. Parameters ------------ eta : float Learning rate (between 0.0 and 1.0) n_iter : int Passes over the training dataset. random_state : int Random number generator seed for random weight initialization. Attributes ----------- w_ : 1d-array Weights after training. errors_ : list Number of misclassifications (updates) in each epoch. """ def __init__(self, eta=0.01, n_iter=50, random_state=1): self.eta = eta self.n_iter = n_iter self.random_state = random_state def train(self, X, y): """Trains the perceptron. Parameters ---------- X : {array-like}, shape = [n_samples, n_features] Training vectors, where n_samples is the number of samples and n_features is the number of features. y : array-like, shape = [n_samples] Target values. Returns ------- self : object """ rgen = np.random.RandomState(self.random_state) self.w_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1]) self.errors_ = [] for _ in range(self.n_iter): errors = 0 for xi, target in zip(X, y): update = self.eta * (target - self.process(xi)) self.w_[1:] += update * xi self.w_[0] += update errors += int(update != 0.0) self.errors_.append(errors) return self def NN_input(self, X): #Calculate net input return np.dot(X, self.w_[1:]) + self.w_[0] def process(self, X): #passing training data to net to get output #Return class label after unit step""" return np.where(self.NN_input(X) >= 0.0, 1, -1)
Step 9: Define the new Python script, Perceptron.py, defines the method display_data() and connect it with the clicked() event from pbData widget as follows:
#Perceptron.py from PyQt5.QtWidgets import * from PyQt5.uic import loadUi from matplotlib.backends.backend_qt5agg import (NavigationToolbar2QT as NavigationToolbar) from matplotlib.colors import ListedColormap from Perceptron_Class import Perceptron import numpy as np import pandas as pd class DemoGUIPerceptron(QMainWindow): def __init__(self): QMainWindow.__init__(self) loadUi("gui_perceptron.ui",self) self.setWindowTitle("GUI Demo of Perceptron") self.pbLoad.clicked.connect(self.display_data) self.addToolBar(NavigationToolbar(self.widgetData.canvas, self)) def load_data(self): df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',header=None) # select setosa and versicolor y = df.iloc[0:100, 4].values self.y = np.where(y == 'Iris-setosa', -1, 1) # extract sepal length and petal length self.X = df.iloc[0:100, [0, 2]].values def display_data(self): self.load_data() # plot data self.widgetData.canvas.axis1.scatter(self.X[:50, 0], \ self.X[:50, 1], color='red', marker='o', label='setosa') self.widgetData.canvas.axis1.scatter(self.X[50:100, 0], \ self.X[50:100, 1], color='blue', marker='x', label='versicolor') self.widgetData.canvas.axis1.set_xlabel('sepal length [cm]') self.widgetData.canvas.axis1.set_ylabel('petal length [cm]') self.widgetData.canvas.axis1.legend(loc='upper left') self.widgetData.canvas.draw() if __name__ == '__main__': import sys app = QApplication(sys.argv) ex = DemoGUIPerceptron() ex.show() sys.exit(app.exec_())
Step 10: Run Perceptron.py script and click the Load Data button. The scatter plot of extracted data will be displayed as shown in Figure below.
Step 11: On gui_perceptron.ui form, add a Spin Box widget and set its minimum, maximum, singleStep, and value properties to 10, 100, 2, and 100. Set its objectName property to sbLength.
Step 12: Then, add a Table Widget onto form and set its objectName property as tableData. Now the form looks as shown in Figure below.
Step 13: Modify load_data() and display_data() functions so that the length of data extracted is determined by value property of sbLength widget as follows:
def load_data(self): df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',header=None) self.dataLength = self.sbLength.value() # select setosa and versicolor y = df.iloc[0:self.dataLength, 4].values self.y = np.where(y == 'Iris-setosa', -1, 1) # extract sepal length and petal length self.X = df.iloc[0:self.dataLength, [0, 2]].values def display_data(self): self.load_data() dataHalf = int(self.dataLength/2) # plot data self.widgetData.canvas.axis1.clear() self.widgetData.canvas.axis1.scatter(self.X[:dataHalf, 0], \ self.X[:dataHalf, 1], color='red', marker='o', label='setosa') self.widgetData.canvas.axis1.scatter(\ self.X[dataHalf:self.dataLength, 0], \ self.X[dataHalf:self.dataLength, 1], color='blue', marker='x', label='versicolor') self.widgetData.canvas.axis1.set_xlabel('sepal length [cm]') self.widgetData.canvas.axis1.set_ylabel('petal length [cm]') self.widgetData.canvas.axis1.legend(loc='upper left') self.widgetData.canvas.draw()
Step 14: Connect valueChanged() signal of sbLength with display_data() function and add it inside __init__() function:
self.sbLength.valueChanged.connect(self.display_data)
Step 15: Define write_df_to_qtable() and display_table() functions to read data frame and display it on table widget.
def display_table(self,df): # show data on table widget self.write_df_to_qtable(df,self.tableData) self.tableData.setHorizontalHeaderLabels(['0',\ '1', '2', '3', 'Name']) self.tableData.setColumnWidth(0, 40) self.tableData.setColumnWidth(1, 40) self.tableData.setColumnWidth(2, 40) self.tableData.setColumnWidth(3, 40) styleH = "::section {""background-color: red; }" self.tableData.horizontalHeader().setStyleSheet(styleH) styleV = "::section {""background-color: yellow; }" self.tableData.verticalHeader().setStyleSheet(styleV) # Takes a df and writes it to a qtable provided. df headers become qtable headers @staticmethod def write_df_to_qtable(df,table): table.setRowCount(df.shape[0]) table.setColumnCount(df.shape[1]) # getting data from df is computationally costly so convert it to array first df_array = df.values for row in range(df.shape[0]): for col in range(df.shape[1]): table.setItem(row, col, \ QTableWidgetItem(str(df_array[row,col])))
Step 16: Invoke display_table() from load_data() function as shown in line 14:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def load_data(self): df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',header=None) self.dataLength = self.sbLength.value() # select setosa and versicolor y = df.iloc[0:self.dataLength, 4].values self.y = np.where(y == 'Iris-setosa', -1, 1) # extract sepal length and petal length self.X = df.iloc[0:self.dataLength, [0, 2]].values #display data on table self.display_table(df) |
Step 17: Run Perceptron.py to see the scatter plot of extracted data and its representation of table as shown in Figure below.
Step 18: Next, add two Widgets onto form and set their objectName properties as widgetDecision and widgetEpoch. Now, the form looks as shown in Figure below.
Step 19: Promote widgetDecision and widgetEpoch to graphics_perceptron class by doing as shown in Step 5 and Step 6.
In the Object Inspector window, you can see that widgetData, widgetDecision and widgetEpoch (graphics_perceptron class) along with the pbLoad object (QPushButton class) are now in the centralwidget object (QWidget class) as shown in Figure below.
def display_epoch(self,ppn): ppn.train(self.X, self.y) self.widgetEpoch.canvas.axis1.clear() self.widgetEpoch.canvas.axis1.plot(range(1, \ len(ppn.errors_) + 1),ppn.errors_, marker='o') self.widgetEpoch.canvas.axis1.set_xlabel('Epochs') self.widgetEpoch.canvas.axis1.set_ylabel('Number of updates') self.widgetEpoch.canvas.draw() def display_decision(self,ppn): self.widgetDecision.canvas.axis1.clear() # setup marker generator and color map markers = ('s', 'x', 'o', '^', 'v') colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan') cmap = ListedColormap(colors[:len(np.unique(self.y))]) # plot the decision surface x1_min, x1_max = self.X[:, 0].min() - 1, self.X[:, 0].max() + 1 x2_min, x2_max = self.X[:, 1].min() - 1, self.X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, 0.01), np.arange(x2_min, x2_max, 0.01)) Z = ppn.process(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) self.widgetDecision.canvas.axis1.contourf(xx1, xx2, Z, \ alpha=0.5, cmap=cmap) self.widgetDecision.canvas.axis1.set_xlim(xx1.min(), xx1.max()) self.widgetDecision.canvas.axis1.set_ylim(xx2.min(), xx2.max()) # plot class samples for idx, cl in enumerate(np.unique(self.y)): self.widgetDecision.canvas.axis1.scatter(\ x=self.X[self.y == cl, 0], y=self.X[self.y == cl, 1], alpha=0.8, c=colors[idx], marker=markers[idx], label=cl, edgecolor='black') self.widgetDecision.canvas.axis1.set_xlabel('sepal length [cm]') self.widgetDecision.canvas.axis1.set_ylabel('petal length [cm]') self.widgetDecision.canvas.axis1.legend(loc='upper left') self.widgetDecision.canvas.draw()
Step 21: Invoke display_epoch() and display_decision() functions in load_data() as shown in line:
def load_data(self): df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',header=None) self.dataLength = self.sbLength.value() # select setosa and versicolor y = df.iloc[0:self.dataLength, 4].values self.y = np.where(y == 'Iris-setosa', -1, 1) # extract sepal length and petal length self.X = df.iloc[0:self.dataLength, [0, 2]].values #display data on table self.display_table(df) #display errors ppn = Perceptron(eta=0.1, n_iter=10) self.display_epoch(ppn) #display decision self.display_decision(ppn)
Step 22: Run Perceptron.py and click on Load Data button. You will see error in every iteration graph and decision regions as shown in Figure below.
Step 23: Change data length and you will get the result as shown in Figure below.
Below is the full script of Perceptron.py:
#Perceptron.py from PyQt5.QtWidgets import * from PyQt5.uic import loadUi from matplotlib.backends.backend_qt5agg import (NavigationToolbar2QT as NavigationToolbar) from matplotlib.colors import ListedColormap from Perceptron_Class import Perceptron import numpy as np import pandas as pd class DemoGUIPerceptron(QMainWindow): def __init__(self): QMainWindow.__init__(self) loadUi("gui_perceptron.ui",self) self.setWindowTitle("GUI Demo of Perceptron") self.pbLoad.clicked.connect(self.display_data) self.addToolBar(NavigationToolbar(self.widgetData.canvas, self)) self.sbLength.valueChanged.connect(self.display_data) def load_data(self): df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',header=None) self.dataLength = self.sbLength.value() # select setosa and versicolor y = df.iloc[0:self.dataLength, 4].values self.y = np.where(y == 'Iris-setosa', -1, 1) # extract sepal length and petal length self.X = df.iloc[0:self.dataLength, [0, 2]].values #display data on table self.display_table(df) #display errors ppn = Perceptron(eta=0.1, n_iter=10) self.display_epoch(ppn) #display decision self.display_decision(ppn) def display_data(self): self.load_data() dataHalf = int(self.dataLength/2) # plot data self.widgetData.canvas.axis1.clear() self.widgetData.canvas.axis1.scatter(self.X[:dataHalf, 0],\ self.X[:dataHalf, 1], color='red', marker='o', label='setosa') self.widgetData.canvas.axis1.scatter(\ self.X[dataHalf:self.dataLength, 0], \ self.X[dataHalf:self.dataLength, 1], color='blue', marker='x', label='versicolor') self.widgetData.canvas.axis1.set_xlabel('sepal length [cm]') self.widgetData.canvas.axis1.set_ylabel('petal length [cm]') self.widgetData.canvas.axis1.legend(loc='upper left') self.widgetData.canvas.draw() def display_table(self,df): # show data on table widget self.write_df_to_qtable(df,self.tableData) self.tableData.setHorizontalHeaderLabels(['0', '1', '2', '3', 'Name']) self.tableData.setColumnWidth(0, 40) self.tableData.setColumnWidth(1, 40) self.tableData.setColumnWidth(2, 40) self.tableData.setColumnWidth(3, 40) styleH = "::section {""background-color: red; }" self.tableData.horizontalHeader().setStyleSheet(styleH) styleV = "::section {""background-color: yellow; }" self.tableData.verticalHeader().setStyleSheet(styleV) # Takes a df and writes it to a qtable provided. df headers become qtable headers @staticmethod def write_df_to_qtable(df,table): table.setRowCount(df.shape[0]) table.setColumnCount(df.shape[1]) # getting data from df is computationally costly so convert it to array first df_array = df.values for row in range(df.shape[0]): for col in range(df.shape[1]): table.setItem(row, col, \ QTableWidgetItem(str(df_array[row,col]))) def display_epoch(self,ppn): ppn.train(self.X, self.y) self.widgetEpoch.canvas.axis1.clear() self.widgetEpoch.canvas.axis1.plot(range(1, \ len(ppn.errors_) + 1),ppn.errors_, marker='o') self.widgetEpoch.canvas.axis1.set_xlabel('Epochs') self.widgetEpoch.canvas.axis1.set_ylabel('Number of updates') self.widgetEpoch.canvas.draw() def display_decision(self,ppn): self.widgetDecision.canvas.axis1.clear() # setup marker generator and color map markers = ('s', 'x', 'o', '^', 'v') colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan') cmap = ListedColormap(colors[:len(np.unique(self.y))]) # plot the decision surface x1_min, x1_max = self.X[:, 0].min() - 1, self.X[:, 0].max() + 1 x2_min, x2_max = self.X[:, 1].min() - 1, self.X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, 0.01), np.arange(x2_min, x2_max, 0.01)) Z = ppn.process(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) self.widgetDecision.canvas.axis1.contourf(xx1, xx2, Z, \ alpha=0.5, cmap=cmap) self.widgetDecision.canvas.axis1.set_xlim(xx1.min(), xx1.max()) self.widgetDecision.canvas.axis1.set_ylim(xx2.min(), xx2.max()) # plot class samples for idx, cl in enumerate(np.unique(self.y)): self.widgetDecision.canvas.axis1.scatter(x=self.X[self.y == cl, 0], y=self.X[self.y == cl, 1], alpha=0.8, c=colors[idx], marker=markers[idx], label=cl, edgecolor='black') self.widgetDecision.canvas.axis1.set_xlabel('sepal length [cm]') self.widgetDecision.canvas.axis1.set_ylabel('petal length [cm]') self.widgetDecision.canvas.axis1.legend(loc='upper left') self.widgetDecision.canvas.draw() if __name__ == '__main__': import sys app = QApplication(sys.argv) ex = DemoGUIPerceptron() ex.show() sys.exit(app.exec_())
Learn From Scratch Neural Networks Using PyQt: Part 2
No comments:
Post a Comment