# Support Vector Machines

Support Vector Machine (SVM) is a technique used for binary classification. Let us consider a categorical data:

from sklearn import datasetsimport matplotlib.pyplot as plt%matplotlib inlineplt.rcParams["figure.dpi"] = 100plt.rcParams["figure.facecolor"] = "white"iris = datasets.load_iris()data = iris.data# data[:4, :]# iris.feature_names# iris.targetsepal_length = data[:, 0]petal_length = data[:, 2]# here we will pick two categories, the dataset has three differnt target valuesplt.scatter(sepal_length[iris.target == 0], petal_length[iris.target == 0])plt.scatter(sepal_length[iris.target == 1], petal_length[iris.target == 1])plt.xlabel("Sepal length (mm)")plt.ylabel("Petal length (mm)")plt.show()

The question is: how can we draw a boundary (here a straight line in two dimensional plane) that separates two categorical data. On an $n$-dimensional dataset, we will have a $(n-1)$ dimensional hyperplane separating the two categories.

$l : b + w_1 x_1 + w_2 x_2 + \dots + w_{n-1} x_{n-1} = 0$

where $w_1^2 + w_2^2 + \dots + w_{n-1}^2 \neq 0$

### Perceptron​

First, let us have a look at the perceptron algorithm. This algorithm finds a linear separator based on Stochastic Gradient Descent. Say we start with an arbitrary line: $w \cdot x + b = 0$ ($w$ and $b$ are parameters), and say our labels $y \in \{-1, +1\}$. Our line should separate our training data points in two parts. The points on one side is $+1$ and on the another $-1$. What could be a suitable loss function? Of course, there are many possibilities. One simple possibility could be, we calculate $w \cdot x + b$, if we are right (i.e., predicts the correct label or $y(w \cdot x + b) > 0$), there is no loss. If we are wrong, we assign loss = $w \cdot x + b$.

Our loss function is convex. We reach for solution by starting with an arbitrary $w$ and $b$, then we go through our data sets and calculate $y(w \cdot x + b) > 0$. If we are right, there is no loss and no update to our $w$ and $b$. If we are wrong, we change $w$ and $b$ along the negative gradient (Stochastic Gradient Descent) by following amount:

$w \rightarrow w + \eta yx$ $b \rightarrow b + \eta y$

where $\eta$ is the step size (learning rate), we could even consider it equal to 1 for simplicity.

We follow this perceptron rule for all data points (called epoch), and start a new epoch by going through the data again. The data points are shuffled before each epoch. Once there are no more updates after going through all the data points, we have reached the solution. If the dataset is linearly separable, perceptron algorithm is guaranteed to find a solution. Notice that the learning process is stochastic, it will produce different outcome each time (albeit each solution will correctly classify our linearly separable dataset).

from sklearn.linear_model import Perceptronmodel = Perceptron(random_state=np.random.randint(100))# choose the data only for category 0 and 1 (i.e., < 2)# here tile creates 4 columns out of single boolean column# later reshape is necessary as it returns a one dimensional arraydata_copy = np.reshape(data[np.tile(np.array([iris.target < 2]).transpose(), \            (1, 4))], (-1, 4))# choose only sepal length and petal length colsX = np.array([data_copy[:, 0], data_copy[:, 2]]).Ty = iris.target[iris.target < 2]model.fit(X, y)# get the separating hyperplanew = model.coef_[0]a = -w[0] / w[1]xx = np.linspace(min(X[:, 0]), max(X[:, 0]))yy = a * xx - (model.intercept_[0]) / w[1]plt.scatter(sepal_length[iris.target == 0], petal_length[iris.target == 0])plt.scatter(sepal_length[iris.target == 1], petal_length[iris.target == 1])plt.plot(xx, yy)plt.xlabel("Sepal length (mm)")plt.ylabel("Petal length (mm)")plt.show()

### Hard margin​

We can see that there are many possible straight lines that perfectly separates our training data points. Then which one to choose? We will pick the one which will have maximum margin. Margin is the distance between the separator line and nearest points on each side. The separator depends only on the points over the margins, and hence the naming support vectors.

from sklearn.svm import SVCmodel = SVC(kernel='linear', C=1000)model.fit(X, y)# get the separating hyperplanew = model.coef_[0]a = -w[0] / w[1]xx = np.linspace(min(X[:, 0]), max(X[:, 0]))yy = a * xx - (model.intercept_[0]) / w[1]# plot the parallels to the separating hyperplane that pass through the# support vectors (margin away from hyperplane in direction# perpendicular to hyperplane). This is sqrt(1+a^2) away vertically in# 2-d.margin = 1 / np.sqrt(np.sum(model.coef_ ** 2))yy_down = yy - np.sqrt(1 + a ** 2) * marginyy_up = yy + np.sqrt(1 + a ** 2) * marginplt.scatter(sepal_length[iris.target == 0], petal_length[iris.target == 0])plt.scatter(sepal_length[iris.target == 1], petal_length[iris.target == 1])plt.plot(xx, yy_down, "--")plt.plot(xx, yy_up, "--")plt.plot(xx, yy)plt.xlabel("Sepal length (mm)")plt.ylabel("Petal length (mm)")plt.show()

### Soft margin​

What happens when the data is not linearly separable? Or even we might want to maximize the margin by giving up some data point (which might well be outliers)?

### Kernel methods​

How do we approach the problem when the data does not represent classes with linear boundary? One of the methods is to expand the data into a higher order space, and then use the linear boundary methods such as SVM. For example, in case of quadratic boundary, we can expand extra basis vectors such as $x_1^2$, $x_2^2$,..., $x_1 x_2$, $x_2 x_3$, ... along with feature space the $x_1$, $x_2$, ... In such a higher dimension, the boundary is linear (though it is quadratic or higher order polynomial in actual feature space).