<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Using Yellow Brick to Explore and Model the Famous Iris Dataset
Exploration Notebook by
Step1:  Terminology
150 observations (n=150)
Step2:  Import the Good Stuff
Step3:  Feature Exploration with RadViz
Step4:  Setosas tend to have the largest septal-width. This can could be a great predictor.
Then, let's remove setosa from the training set and see fi we can find any differentiation between veriscolor and virginica.
Remove Setosa from the training set
Step5:  Try the Covariance Visualizer
Step6:  This covariance chart is not intereptatble as they don't have labels. Also there shouldn't be half numbers in labels.
More Feature Exploration
Step7:  This clearly demonstrates the separation between features - especially petal_length and petal_width. One concern is that this demonstraction data might be obsured by the scaling of the features and add noise to the intepretation.  
Feature Exploration
Step8:  The scaled dataset makes it easier to see the separation between classes for each of the features.
*TODO - Add scaling option to PararalCordinates and potentially other visualizers
Now that we have some features, Let's Evaluate Classifiers
From the feature selection phase, we determined that petal_length and petal_width seem to have the best separation.
Step9:  Note
Step10:  Model Selection
<ASSISTANT_TASK:>
Python Code:
# read the iris data into a DataFrame
import pandas as pd
url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
col_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species']
iris = pd.read_csv(url, header=None, names=col_names)
iris.head()
Explanation: Using Yellow Brick to Explore and Model the Famous Iris Dataset
Exploration Notebook by:
Nathan Danielsen
Prema Damodaran
Review of the iris dataset
End of explanation
# map each iris species to a number
iris['species_num'] = iris.species.map({'Iris-setosa':0, 'Iris-versicolor':1, 'Iris-virginica':2})
Explanation: Terminology
150 observations (n=150): each observation is one iris flower
4 features (p=4): sepal length, sepal width, petal length, and petal width
Response: iris species
Classification problem since response is categorical
Lightly Preprocess the Dataset
End of explanation
import yellowbrick as yb 
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['figure.figsize'] = (12, 8)
from yellowbrick.features.rankd import Rank2D
from yellowbrick.features.radviz import RadViz
from yellowbrick.features.pcoords import ParallelCoordinates
Explanation: Import the Good Stuff
End of explanation
# Specify the features of interest and the classes of the target
features = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
y = iris.species_num.as_matrix()
visualizer = RadViz(classes=classes, features=features)
visualizer.fit(X, y)      # Fit the data to the visualizer
visualizer.transform(X)   # Transform the data
visualizer.poof()         # Draw/show/poof the data
Explanation: Feature Exploration with RadViz
End of explanation
# Specify the features of interest and the classes of the target
iris_subset = iris[iris.species_num!=0]
features = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
classes = ['Iris-setosa','Iris-versicolor', 'Iris-virginica'] # but have to leave in more than two classes 
# Extract the numpy arrays from the data frame
X = iris_subset[features].as_matrix()
y = iris_subset.species_num.as_matrix()
assert y.shape[0] == X.shape[0]
visualizer = RadViz(classes=classes, features=features)
visualizer.fit(X, y)      # Fit the data to the visualizer
visualizer.transform(X)   # Transform the data
visualizer.poof()         # Draw/show/poof the data
Explanation: Setosas tend to have the largest septal-width. This can could be a great predictor.
Then, let's remove setosa from the training set and see fi we can find any differentiation between veriscolor and virginica.
Remove Setosa from the training set
End of explanation
# Specify the features of interest and the classes of the target
features = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
y = iris.species_num.as_matrix()
visualizer = Rank2D(features=features, algorithm='covariance')
visualizer.fit(X, y)      # Fit the data to the visualizer
visualizer.transform(X)   # Transform the data
visualizer.poof()         # Draw/show/poof the data
Explanation: Try the Covariance Visualizer
End of explanation
features = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
y = iris.species_num.values
assert y.shape[0] == X.shape[0]
visualizer = ParallelCoordinates(classes=classes, features=features)
visualizer.fit(X, y)      # Fit the data to the visualizer
visualizer.transform(X)   # Transform the data
visualizer.poof()         # Draw/show/poof the data
Explanation: This covariance chart is not intereptatble as they don't have labels. Also there shouldn't be half numbers in labels.
More Feature Exploration: Look at Parallel Coodinates for all Species
End of explanation
from sklearn import preprocessing
features = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
X_scaled = preprocessing.scale(X)
y = iris.species_num.values
assert y.shape[0] == X.shape[0]
visualizer = ParallelCoordinates(classes=classes, features=features)
visualizer.fit(X_scaled, y)      # Fit the data to the visualizer
visualizer.transform(X)   # Transform the data
visualizer.poof()       
Explanation: This clearly demonstrates the separation between features - especially petal_length and petal_width. One concern is that this demonstraction data might be obsured by the scaling of the features and add noise to the intepretation.  
Feature Exploration: ParallelCoordinates with Scaling
End of explanation
# Classifier Evaluation Imports
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from yellowbrick.classifier import ClassificationReport, ClassBalance
features = ['petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
y = iris.species_num.as_matrix()
assert y.shape[0] == X.shape[0]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
assert y_train.shape[0] == X_train.shape[0]
assert y_test.shape[0] == X_test.shape[0]
# Instantiate the classification model and visualizer
bayes = GaussianNB()
visualizer = ClassificationReport(bayes, classes=classes)
visualizer.fit(X_train, y_train)  # Fit the training data to the visualizer
visualizer.score(X_test, y_test)  # Evaluate the model on the test data
g = visualizer.poof()             # Draw/show/poof the data
visualizer
Explanation: The scaled dataset makes it easier to see the separation between classes for each of the features.
*TODO - Add scaling option to PararalCordinates and potentially other visualizers
Now that we have some features, Let's Evaluate Classifiers
From the feature selection phase, we determined that petal_length and petal_width seem to have the best separation.
End of explanation
# Classifier Evaluation Imports
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from yellowbrick.classifier import ClassificationReport, ClassBalance
features = ['petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
y = iris.species_num.as_matrix()
assert y.shape[0] == X.shape[0]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
assert y_train.shape[0] == X_train.shape[0]
assert y_test.shape[0] == X_test.shape[0]
# Instantiate the classification model and visualizer
bayes = MultinomialNB()
visualizer = ClassificationReport(bayes)# classes=classes)
visualizer.fit(X_train, y_train)  # Fit the training data to the visualizer
visualizer.score(X_test, y_test)  # Evaluate the model on the test data
g = visualizer.poof()             # Draw/show/poof the data
Explanation: Note: There seems to be some sort of bug in the draw/ fit methods. 
Let's try a naive bayes as the other didn't wrok
End of explanation
features = ['petal_length', 'petal_width']
classes = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
# Extract the numpy arrays from the data frame
X = iris[features].as_matrix()
y = iris.species_num.as_matrix()
assert y.shape[0] == X.shape[0]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)
assert y_train.shape[0] == X_train.shape[0]
assert y_test.shape[0] == X_test.shape[0]
test = pd.DataFrame(y_test, columns=['species'])
test.species.value_counts() # The test train split provides unbalanced classes
from sklearn.ensemble import RandomForestClassifier
from yellowbrick.classifier import ClassificationReport
# Instantiate the classification model and visualizer
forest = RandomForestClassifier()
visualizer = ClassBalance(forest, classes=classes)
visualizer.fit(X_train, y_train)  # Fit the training data to the visualizer
visualizer.score(X_test, y_test)  # Evaluate the model on the test data
g = visualizer.poof()             # Draw/show/poof the data
Explanation: Model Selection: Random Forest Classification
End of explanation
<END_TASK>