"""
**Kindly upvote !! This will make my day.....**
"""
#The following is an example for creating an SVM classifier by using kernels. We will be using iris dataset from scikit-learn −

import pandas as pd
import numpy as np
from sklearn import svm,datasets
import matplotlib.pyplot as plt

#load the input data
iris = datasets.load_iris()
#From the dataset we are taking first two features

X = iris.data[:, :2]
y = iris.target

#Next we will plot SVM boundries with original data
x_min , x_max =  X[:,0].min() - 1, X[:,0].max()+1
y_min , y_max = X[:,1].min() -1, X[:,1].max()+1

h = (x_max/x_min)/100

xx , yy = np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))

X_plot = np.c_[xx.ravel(),yy.ravel()]
#Now, we need to provide the value of regularization parameter
c = 1.0

#Next, SVM classifier object can be created as follows −

svc_classifier = svm.SVC(kernel='linear', C=c).fit(X, y)

Z = svc_classifier.predict(X_plot)
Z = Z.reshape(xx.shape)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contourf(xx, yy, Z, cmap=plt.cm.tab10, alpha=0.3)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.title('Support Vector Classifier with linear kernel')
import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def generate_random_dataset(size):
    """ Generate a random dataset and that follows a quadratic  distribution
    """
    x = []
    y = []
    target = []   
    for i in range(size):
        # class zero
        x.append(np.round(random.uniform(0, 2.5), 1))
        y.append(np.round(random.uniform(0, 20), 1))
        target.append(0)        
        # class one
        x.append(np.round(random.uniform(1, 5), 2))
        y.append(np.round(random.uniform(20, 25), 2))
        target.append(1)        
        x.append(np.round(random.uniform(3, 5), 2))
        y.append(np.round(random.uniform(5, 25), 2))
        target.append(1)    
    df_x = pd.DataFrame(data=x)
    df_y = pd.DataFrame(data=y)
    df_target = pd.DataFrame(data=target)    
    data_frame = pd.concat([df_x, df_y], ignore_index=True, axis=1)
    data_frame = pd.concat([data_frame, df_target], ignore_index=True, axis=1)    
    data_frame.columns = ['x', 'y', 'target']
    return data_frame


# Generate dataset
size = 100
dataset = generate_random_dataset(size)
features = dataset[['x', 'y']]
label = dataset['target']

# Hold out 20% of the dataset for training
test_size = int(np.round(size * 0.2, 0))

# Split dataset into training and testing sets
x_train = features[:-test_size].values
y_train = label[:-test_size].values

x_test = features[-test_size:].values
y_test = label[-test_size:].values

# Plotting the training set
fig, ax = plt.subplots(figsize=(12, 7))

# removing to and right border
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)

# adding major gridlines
ax.grid(color='grey', linestyle='-', linewidth=0.25, alpha=0.5)
ax.scatter(features[:-test_size]['x'], features[:-test_size]['y'], color="#8C7298")
plt.show()
"""There is a little space between two groups of data points.
But closer to the center,it's not clear which data point belong to which class.

A quadratic curve might be a good candidate to separate these classes.
"""


from sklearn import svm
model = svm.SVC(kernel = 'poly',degree=2)
model.fit(x_train,y_train)
""" To see the result of fitting this model, we can plot the decision boundary and the margin along with the dataset."""

fig,ax = plt.subplots(figsize= (12,7))

#Removing to and right borders
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)

#Create grid to eval model
xx = np.linspace(-1,max(features['x'])+1,len(x_train))
yy = np.linspace(0, max(features['y']) + 1, len(y_train))
YY,XX = np.meshgrid(yy,xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T

train_size = len(features[:-test_size]['x'])

# Assigning different colors to the classes
colors = y_train
colors = np.where(colors == 1, '#8C7298', '#4786D1')

# Plot the dataset
ax.scatter(features[:-test_size]['x'], features[:-test_size]['y'], c=colors)

# Get the separating hyperplane
Z = model.decision_function(xy).reshape(XX.shape)
# Draw the decision boundary and margins
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])

# Highlight support vectors with a circle around them
ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=100, linewidth=1, facecolors='none', edgecolors='k')

plt.show()
""" If we calculate the accuracy of this model against the testing set we get a good result, 
granted the dataset is very small and generated at random """

from sklearn.metrics import accuracy_score
predictions_poly = model.predict(x_test)
accuracy_poly = accuracy_score(y_test, predictions_poly)
print("2nd degree polynomial Kernel\nAccuracy (normalized): " + str(accuracy_poly))

"""The accuracy is good, but let's see if a more simplistic approach could have solved our problem.
 To fit an SVM with a linear kernel we just need to update the kernel parameter.
 """

model = svm.SVC(kernel='linear')
model.fit(x_train,y_train)
fig,ax = plt.subplots(figsize= (12,7))

#Removing to and right borders
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)

#Create grid to eval model
xx = np.linspace(-1,max(features['x'])+1,len(x_train))
yy = np.linspace(0, max(features['y']) + 1, len(y_train))
YY,XX = np.meshgrid(yy,xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T

train_size = len(features[:-test_size]['x'])

# Assigning different colors to the classes
colors = y_train
colors = np.where(colors == 1, '#8C7298', '#4786D1')

# Plot the dataset
ax.scatter(features[:-test_size]['x'], features[:-test_size]['y'], c=colors)

# Get the separating hyperplane
Z = model.decision_function(xy).reshape(XX.shape)
# Draw the decision boundary and margins
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])

# Highlight support vectors with a circle around them
ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=100, linewidth=1, facecolors='none', edgecolors='k')

plt.show()
print("2nd degree polynomial Kernel\nAccuracy (normalized): " + str(accuracy_poly))
