"""
# Topics
1. About Iris dataset
2. Exploring the Iris dataset
3. iris data visualization
4. Supervised learning on Iris dataset
"""
"""
# 1. About  iris Dataset
"""
from IPython.display import Image
Image('../input/iris-measurement/iris_measurements.png')
"""
- The iris dataset contains the following data
     - 50 samples of 3 different species of iris (150 samples total)
- Measurements: sepal length, sepal width, petal length, petal width
     - The format for the data: (sepal length, sepal width, petal length, petal width)
"""
"""
# 2. Exploring the iris datset

"""
# importing required modules
import numpy as np
import pandas as pd
# importing visualization maodules
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
from mpl_toolkits import mplot3d
from sklearn.tree import plot_tree
import plotly.express as px
import plotly.graph_objects as go
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score,KFold,StratifiedKFold
# importing MachineLearning Algorithms
from sklearn.preprocessing import LabelEncoder,MinMaxScaler,StandardScaler
from sklearn.linear_model import LinearRegression,Ridge,Lasso
from sklearn.naive_bayes import MultinomialNB,BernoulliNB,GaussianNB
from sklearn.linear_model import LogisticRegression,PassiveAggressiveClassifier
from sklearn.svm import SVC,SVR
from sklearn.tree import DecisionTreeClassifier,DecisionTreeRegressor
# importing ensembling algorithms
from sklearn.ensemble import RandomForestRegressor,RandomForestClassifier,AdaBoostClassifier,ExtraTreesClassifier,GradientBoostingClassifier,BaggingClassifier
from sklearn.cluster import KMeans
from sklearn.neighbors import KNeighborsClassifier,KNeighborsRegressor,RadiusNeighborsClassifier
from sklearn.decomposition import PCA,TruncatedSVD
import warnings
warnings.filterwarnings("ignore")
# overview of the data
### Reading the iris dataset
data=pd.read_csv('../input/iris/Iris.csv')
data.head(3)
# checking whether our dataset has any null values
print(data.isnull().sum())
"""
# 3. iris data visualization
1. We will visualize the data using seaborn,matplotlib,plotly
"""
sns.pairplot(data.drop(['Id'],axis="columns"),hue='Species')
plt.show()
fig=plt.figure(figsize=(20,20))
data.drop(['Id'],axis="columns").plot(kind="kde",subplots=True,ax=plt.gca())
plt.show()
fig=plt.figure(figsize=(15,15))
data.drop(['Id'],axis="columns").plot(kind="hist",subplots=True,ax=plt.gca())
plt.title(' histogram plotting of all the data')
plt.show()
fig=plt.figure(figsize=(10,10))
ax=plt.gca()
data.drop(['Id'],axis="columns").hist(edgecolor='black', linewidth=1.2,ax=ax)
plt.title('histogram plotting of numerical data in iris dataset')
plt.show()
def plot_scatter(feature1,feature2,title):
    fig=px.scatter(data,x=feature1,y=feature2,color='Species',title=title,hover_data=['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm',
       'Species'],template="plotly_dark")
    fig.show()
plot_scatter(feature1='SepalLengthCm',feature2='SepalWidthCm',title='SepalLengthCm vs SepalWidthCm')
plot_scatter(feature1='PetalLengthCm',feature2='PetalWidthCm',title='PetalLengthCm vs PetalWidthCm')
plot_scatter(feature1='SepalLengthCm',feature2='PetalLengthCm',title='SepalLengthCm vs PetalLengthCm')
plot_scatter(feature1='SepalWidthCm',feature2='PetalWidthCm',title='SepalWidthCm vs PetalWidthCm')
def plot_bar(feature1,feature2,title):
    fig=px.bar(data,x=feature1,y=feature2,color='Species',title=title,hover_data=['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm',
       'Species'],template="plotly_dark")
    fig.show()
plot_bar(feature1='SepalLengthCm',feature2='PetalWidthCm',title='SepalLengthCm vs PetalWidthCm')
plot_bar(feature1='SepalWidthCm',feature2='PetalLengthCm',title='SepalWidthCm vs PetalLengthCm')
plot_bar(feature1='PetalLengthCm',feature2='SepalWidthCm',title='PetalLengthCm vs SepalWidthCm')
plot_bar(feature1='PetalWidthCm',feature2='SepalLengthCm',title='PetalWidthCm vs SepalLengthCm')
def pie_chart_rep(values,names,title):
    fig = px.pie(data, values=values, names=names, title=title,template="plotly_dark")
    fig.update_layout()
    fig.show()
pie_chart_rep(values='SepalLengthCm',names='Species',title='pie representation of SepalLengthCm and Species')
pie_chart_rep(values='SepalWidthCm',names='Species',title='pie representation of SepalWidthCm and Species')
pie_chart_rep(values='PetalLengthCm',names='Species',title='pie representation of PetalLengthCm and Species')
pie_chart_rep(values='PetalWidthCm',names='Species',title='pie representation of PetalWidthCm and Species')
fig = go.Figure()
fig.add_trace(go.Scatter(x=data.Species, y=data.SepalLengthCm,mode='markers', name='SepalLengthCm'))
fig.add_trace(go.Scatter(x=data.Species, y=data.SepalWidthCm,mode='markers', name='SepalWidthCm'))
fig.add_trace(go.Scatter(x=data.Species, y=data.PetalLengthCm,mode='markers', name='PetalLengthCm'))
fig.add_trace(go.Scatter(x=data.Species, y=data.PetalWidthCm,mode='markers', name='PetalWidthCm'))
fig.update_layout(template="plotly_dark",title='specifying the species based on SepalLengthCm')
fig.show()               
fig=plt.figure(figsize=(10,10))
plt.subplot(2,2,1)
sns.swarmplot(x='Species',y='PetalLengthCm',data=data)
plt.legend()
plt.subplot(2,2,2)
sns.swarmplot(x='Species',y='PetalWidthCm',data=data)
plt.legend()
plt.subplot(2,2,3)
sns.swarmplot(x='Species',y='SepalLengthCm',data=data)
plt.legend()
plt.subplot(2,2,4)
sns.swarmplot(x='Species',y='SepalWidthCm',data=data)
plt.legend()
plt.show()
"""
# 4. Supervised learning on Iris dataset
 **Supervised learning:** Supervised learning is the machine learning task of learning a function that maps an input to an output based on example input-output pairs. It infers a function from labeled training data consisting of a set of training examples.Supervised learning is divided into Regression and Classification.
-  **Regression:** Regression is the process of finding a model or function for distinguishing the data into continuous real values instead of using classes or discrete values. It can also identify the distribution movement depending on the historical data. Because a regression predictive model predicts a quantity, therefore, the skill of the model must be reported as an error in those predictions
-   **Classification:** Classification is the process of finding or discovering a model or function which helps in     -separating the data into multiple categorical classes i.e. discrete values. In classification, data is categorized under different labels according to some parameters given in input and then the labels are predicted for the data.


##### Before we go into Supervised learning we must know something called feature engineering:
- Feature Selection is one of the core concepts in machine learning which hugely impacts the performance of your model. The data features that you use to train your machine learning models have a huge influence on the performance you can achieve.
- Irrelevant or partially relevant features can negatively impact model performance.
- Feature selection and Data cleaning should be the first and most important step of your model designing.

How to select features and what are Benefits of performing feature selection before modeling your data?

1. Reduces Overfitting: Less redundant data means less opportunity to make decisions based on noise.

2. Improves Accuracy: Less misleading data means modeling accuracy improves.

3. Reduces Training Time: fewer data points reduce algorithm complexity and algorithms train faster.


Also, we must know two terms (
feature_names ---> feature_names are variables that are used to determine the classification process in this iris dataset we use SepalLengthCm,SepalWidthCm,PetalLengthCm,PetalWidthCm as feature_names
and 
target ---> the target variables are the output variable in this dataset we use Species as target
)
"""
"""
### Label Encoding for Species target variable
"""
# we convert the categorial data into numerical data using LabelEncoder()
le=LabelEncoder()
data['SpeciesCategory']=le.fit_transform(data['Species'])
label={0:'Iris-setosa',1:'Iris-versicolor',2:'Iris-virginica'}
"""
- we will look at some of the most used machine learning supervised classifier algorithms such as
    - KNN Classifier
    - RadiusNeighborsClassifier
    - SVM Classifier
    - Naive-Bayes Classifier
    - DecisionTreeClassifier
    - RandomForestClassifier
    - LogisticRegressor
"""
"""
# To process supervised learning algorithms
"""
"""
- step1: we will first split the data into training and testing data and will divide in 7:3 ratio
- step2: And now we will train the model using X_train and y_train with fit() function
- step3: we will predict the X_test data using predict() function 
- step4: and then we'll find the accuracy of trained and predicted data using score() function
"""
# we choose feature_names and target values from the data and split the data into train and test data
X=data.drop(['Species','SpeciesCategory'],axis='columns')
y=data['SpeciesCategory']
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0,test_size=0.3)
"""
# KNN Classifier
- K-Nearest Neighbors (KNN) is one of the simplest algorithms used in Machine Learning for regression and classification problem. KNN algorithms use data and classify new data points based on similarity measures (e.g. distance function). Classification is done by a majority vote to its neighbors. The data is assigned to the class which has the nearest neighbors. As you increase the number of nearest neighbors, the value of k, accuracy might increase.
"""
#Classification using KNeighborsClassifier and we will take nearest neighbors as 5
knn_clf=KNeighborsClassifier(n_neighbors=5)
knn_clf.fit(X_train,y_train)
print("the predicted values of X_test are {}".format(knn_clf.predict(X_test)))
print("the accuracy score of trained data for KNN classifier is {}".format(knn_clf.score(X_train,y_train)))
print("the accuracy score of test and predicted data for KNN classifier is {}".format(knn_clf.score(X_test,knn_clf.predict(X_test))))
# plotting KNN for iris dataset
fig=px.scatter(data,x='PetalLengthCm',y='PetalWidthCm',color='Species',title='PetalLengthCm vs PetalWidthCm in KNN Classifier',size='PetalWidthCm',hover_data=['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm','Species'],template="plotly_dark")
fig.show()
"""
######  if we see plotting PetalLengthCm vs PetalWidthCm gives some good visualization we could easily identify our species based on PetalLengthCm vs PetalWidthCm through visualization also there is no outliers in those features
"""
# plotting accuracy for a range of numbers 
accuracy=[]
n_neighbors_range=range(1,10)
for i in n_neighbors_range:
    knn_clf=KNeighborsClassifier(n_neighbors=i)
    knn_clf.fit(X_train,y_train)
    accuracy.append(knn_clf.score(X_train,y_train))
px.line(n_neighbors_range,accuracy,title='n_neighbors_range vs accuracy',template='plotly_dark')
"""
###### also after plotting n_neighbors_range to accuracy shows that for any value of n_neighbors we are getting an accuracy of 1.
"""
"""
# RadiusNeighborsClassifier
- **RadiusNeighborsClassifier:** RadiusNeighborsClassifier implements learning based on the number of neighbors within a fixed radius 'r' of each training point, where 'r' is a floating-point value specified by the user.
- It is very much similar to KNN classifier only difference we commonly consider is, in KNN Classifier we use n_neighbors as a key factor but in RadiusNeighborsClassifier we use radius as a key factor it classifier the data based on a radius value given. 
"""
radius_clf=RadiusNeighborsClassifier(radius=10)
radius_clf.fit(X_train,y_train)
print("the predicted values of X_test are {}".format(radius_clf.predict(X_test)))
print("the accuracy score of trained data for radius neighbors classifier is {}".format(radius_clf.score(X_train,y_train)))
print("the accuracy score of test and predicted data for radius neighbors  classifier is {}".format(radius_clf.score(X_test,radius_clf.predict(X_test))))
accuracy=[]
radius_range=range(1,20)
for i in radius_range:
    radius_clf=RadiusNeighborsClassifier(radius=i)
    radius_clf.fit(X_train,y_train)
    accuracy.append(radius_clf.score(X_train,y_train))
px.line(radius_range,accuracy,title='radius vs accuracy',template='plotly_dark')
"""
###### we could see the accuracy values changes with radius value
"""
"""
# SVM Classifier
-  “Support Vector Machine” (SVM) is a supervised machine learning algorithm which can be used for both classification or regression challenges. However,  it is mostly used in classification problems. In the SVM algorithm, we plot each data item as a point in n-dimensional space (where n is number of features you have) with the value of each feature being the value of a particular coordinate. Then, we perform classification by finding the hyper-plane that differentiates the two classes very well.


"""
svm_clf=SVC()
svm_clf.fit(X_train,y_train)
print("the predicted values of X_test are {}".format(svm_clf.predict(X_test)))
print("the accuracy score of trained data for SVM is {}".format(svm_clf.score(X_train,y_train)))
print("the accuracy score of test and predicted data for SVM is {}".format(svm_clf.score(X_test,svm_clf.predict(X_test))))
# plotting accuracy for a range of numbers 
accuracy=[]
c=range(1,10)
for i in c:
    svm_clf=KNeighborsClassifier(n_neighbors=i)
    svm_clf.fit(X_train,y_train)
    accuracy.append(svm_clf.score(X_train,y_train))
px.line(n_neighbors_range,accuracy,title='Regularization factor(C) vs accuracy',template='plotly_dark')
"""
###### also after plotting n_neighbors_range to accuracy shows that for any value of n_neighbors we are getting an accuracy of 1.
"""
"""
# Naive-Bayes Classifier
- we apply Naive-Bayes Classifier for three types of Naive-Bayes:

    - Gaussian: It is used in classification and it assumes that features follow a normal distribution.
    - Multinomial: It is used for discrete counts. 
    - Bernoulli: The binomial model is useful if your feature vectors are binary (i.e. zeros and ones).
- Naive Bayes is a probabilistic machine learning model which is used as a classifier. It comes under Supervised learning algorithms.
- The intuition behind this algorithm is Bayes theorem. Bayes theorem tells the probability of an event occurring given the probability of another event that has been already occurred. Below is the mathematical equation of Bayes theorem.
"""
mnb=MultinomialNB()
bnb=BernoulliNB()
gnb=GaussianNB()
mnb.fit(X_train,y_train)
bnb.fit(X_train,y_train)
gnb.fit(X_train,y_train)
print("the accuracy score of trained data for MultinomialNB is {}".format(mnb.score(X_train,y_train)))
print("the accuracy score of test and predicted data for MultinomialNB is {}".format(mnb.score(X_test,mnb.predict(X_test))))
print("the accuracy score of trained data for BernoulliNB is {}".format(bnb.score(X_train,y_train)))
print("the accuracy score of test and predicted data for BernoulliNB is {}".format(bnb.score(X_test,bnb.predict(X_test))))
print("the accuracy score of trained data for GaussianNB is {}".format(gnb.score(X_train,y_train)))
print("the accuracy score of test and predicted data for GaussianNB is {}".format(gnb.score(X_test,gnb.predict(X_test))))
"""
# DecisionTreeClassifer
- **Decision Tree :** Decision tree is the most powerful and popular tool for classification and prediction. A Decision tree is a flowchart like tree structure, where each internal node denotes a test on an attribute, each branch represents an outcome of the test, and each leaf node (terminal node) holds a class label.
- The strengths of decision tree methods are:
   - Decision trees are able to generate understandable rules.
   - Decision trees perform classification without requiring much computation.
   - Decision trees are able to handle both continuous and categorical variables.
   - Decision trees provide a clear indication of which fields are most important for prediction or classification.


"""
dec_tree=DecisionTreeClassifier(max_depth=10)
dec_tree.fit(X_train,y_train)
print("predicted data is:",svm_clf.predict(X_test))
print("the accuracy score of trained data for DecisionTreeClassifier is {}".format(svm_clf.score(X_train,y_train)))
print("the accuracy score of test and predicted data for DecisionTreeClassifier is {}".format(svm_clf.score(X_test,svm_clf.predict(X_test))))
from sklearn import tree
fig=plt.figure(figsize=(10,10))
_=tree.plot_tree(dec_tree,feature_names=data.PetalLengthCm,class_names=data.Species,filled=True)
plt.title('DecisionTreeClassifier for PetalLengthCm vs Species')
fig.show()
"""
- Above Decision tree Classifies data based on MSE(Mean Squared Error) and 'gini' value
- A tree can be “learned” by splitting the source set into subsets based on an attribute value test. This process is repeated on each derived subset in a recursive manner called recursive partitioning. The recursion is completed when the subset at a node all has the same value of the target variable, or when splitting no longer adds value to the predictions. 
"""
# plotting accuracy for a range of numbers 
accuracy=[]
max_depth=range(1,10)
for i in max_depth:
    dec_tree=KNeighborsClassifier(n_neighbors=i)
    dec_tree.fit(X_train,y_train)
    accuracy.append(dec_tree.score(X_test,svm_clf.predict(X_test)))
px.line(max_depth,accuracy,title='max_depth of the tree vs accuracy',template='plotly_dark')
"""
######  also after plotting max_depth to accuracy shows that for any value of n_neighbors we are getting an accuracy of 1.
"""
"""
# RandomForestClassifier
**RandomForestClassifier:** Random forest is a supervised learning algorithm which is used for both classification as well as regression. But however, it is mainly used for classification problems. As we know that a forest is made up of trees and more trees means more robust forest. Similarly, random forest algorithm creates decision trees on data samples and then gets the prediction from each of them and finally selects the best solution by means of voting. It is an ensemble method which is better than a single decision tree because it reduces the over-fitting by averaging the result.
- We can understand the working of Random Forest algorithm with the help of following steps −

   - Step 1 − First, start with the selection of random samples from a given dataset.

   - Step 2 − Next, this algorithm will construct a decision tree for every sample. Then it will get the prediction result from every decision tree.

   - Step 3 − In this step, voting will be performed for every predicted result.

   - Step 4 − At last, select the most voted prediction result as the final prediction result.
"""
forest_clf=RandomForestClassifier(n_estimators=5)
forest_clf.fit(X_train,y_train)
print("the predicted values are:",forest_clf.predict(X_test))
print("the accuracy score of trained data for DecisionTreeClassifier is",forest_clf.score(X_train,y_train))
print("the accuracy score of tested and predicted data for DecisionTreeClassifier is",forest_clf.score(X_test,forest_clf.predict(X_test)))
fig=plt.figure(figsize=(10,10))
_=tree.plot_tree(forest_clf.estimators_[3],feature_names=data.PetalLengthCm,class_names=data.Species)
plt.title("random forest tree PetalLengthCm vs PetalLengthCm")
plt.show()
"""
######  Above Decision tree Classifies data based on MSE(Mean Squared Error) and 'gini' value
"""
# plotting accuracy for a range of numbers 
accuracy=[]
n_estimators=range(1,10)
for i in n_estimators:
    forest_clf=RandomForestClassifier(n_estimators=5)
    forest_clf.fit(X_train,y_train)
    accuracy.append(forest_clf.score(X_test,forest_clf.predict(X_test)))
px.line(n_estimators,accuracy,title='n_estimators of the random forest classifier vs accuracy',template='plotly_dark')
"""
###### also after plotting n_estimators to accuracy shows that for any value of n_estimators we are getting an accuracy of 1.
"""
"""
# LogisticRegression
- Types of Logistic Regression
    - Generally, logistic regression means binary logistic regression having binary target variables, but there can be two more categories of target variables that can be predicted by it. Based on those number of categories, Logistic regression can be divided into following types:

    - **Binary or Binomial:** In such a kind of classification, a dependent variable will have only two possible types either 1 and 0. 
    - **Multinomial:** In such a kind of classification, dependent variable can have 3 or more possible unordered types or the types having no quantitative significance.
    - **Ordinal:** In such a kind of classification, dependent variable can have 3 or more possible ordered types or the types having a quantitative significance. For example, these variables may represent “poor” or “good”, “very good”, “Excellent” and each category can have the scores like 0,1,2,3.
 ### For this iris dataset we will use Multinomial types of LogisticRegression
"""
log_reg=LogisticRegression(C=100)
log_reg.fit(X_train,y_train)
print("the predicted values are:",log_reg.predict(X_test))
print("the accuracy score of trained data for DecisionTreeClassifier is",log_reg.score(X_train,y_train))
print("the accuracy score of tested and predicted data for DecisionTreeClassifier is",log_reg.score(X_test,log_reg.predict(X_test)))
C_range=range(1,200)
accuracy=[]
for n in C_range:
    log_reg=LogisticRegression(C=n)
    log_reg.fit(X_train,y_train)
    accuracy.append(log_reg.score(X_test,log_reg.predict(X_test)))
px.line(C_range,accuracy,title='Regularization factor(C) of the tree vs accuracy',template='plotly_dark')
"""
###### also after plotting Regularization factor(C) to accuracy shows that for any value of n_neighbors we are getting an accuracy of 1.
"""
"""
<h1>***********  Please <font color='red'>UPVOTE</font color> if you like my work  ****************
"""
"""
<h1><font color='brown'>                   Thank you!!!!!!!!!!!!!!!!
"""