Loading...

Iris

This example uses the iris dataset to predict the species of various flowers based on their physical features. You can download the Jupyter Notebook of the study here.

  • PetalLengthCm: Petal Length in cm

  • PetalWidthCm: Petal Width in cm

  • SepalLengthCm: Sepal Length in cm

  • SepalWidthCm: Sepal Width in cm

  • Species: The Flower Species (Setosa, Virginica, Versicolor)

We will follow the data science cycle (Data Exploration - Data Preparation - Data Modeling - Model Evaluation - Model Deployment) to solve this problem.

Initialization

This example uses the following version of VerticaPy:

import verticapy as vp

vp.__version__
Out[2]: '1.1.0'

Connect to Vertica. This example uses an existing connection called VerticaDSN . For details on how to create a connection, see the Connection tutorial.

You can skip the below cell if you already have an established connection.

vp.connect("VerticaDSN")

Let’s create a Virtual DataFrame of the dataset.

from verticapy.datasets import load_iris

iris = load_iris()
iris.head(5)
123
SepalLengthCm
Numeric(5,2)
100%
...
123
PetalWidthCm
Numeric(5,2)
100%
Abc
Species
Varchar(30)
100%
14.6...0.2Iris-setosa
24.7...0.2Iris-setosa
34.7...0.2Iris-setosa
44.8...0.1Iris-setosa
54.8...0.2Iris-setosa

Data Exploration and Preparation

Let’s explore the data by displaying descriptive statistics of all the columns.

iris.describe(method = "categorical", unique = True)
...
top_percent
unique
"SepalLengthCm"...20.436.0
"SepalWidthCm"...20.025.0
"PetalLengthCm"...22.444.0
"PetalWidthCm"...24.823.0
"Species"...40.03.0

We don’t have much data here, but that’s okay; since different flower species have different proportions and ratios between those proportions, we can start by making ratios between each feature.

We’ll need to use the One-Hot Encoder on the Species to get information about each species.

iris["Species"].one_hot_encode(drop_first = False)
iris["ratio_pwl"] = iris["PetalWidthCm"] / iris["PetalLengthCm"]
iris["ratio_swl"] = iris["SepalWidthCm"] / iris["SepalLengthCm"]

We can draw the correlation matrix (Pearson correlation coefficient) of the new features to see if there are some linear links.

iris.corr()

The Iris setosa is highly linearly correlated with the petal length and the sepal ratio. We can see a perfect separation using the two features (though we can also see this separation the petal length alone).

iris.scatter(
    columns = ["PetalLengthCm", "ratio_swl"],
    by = "Species",
)

We can we a clear linear separation between the Iris setosa and the other species, but we’ll need more features to identify the differences between Iris virginica and Iris versicolor.

iris.scatter(
    columns = [
        "PetalLengthCm",
        "PetalWidthCm",
        "SepalLengthCm",
    ],
    by = "Species",
)

Our strategy is simple: we’ll use two Linear Support Vector Classification (SVC): one to classify the Iris setosa and another to classify the Iris versicolor.

Machine Learning

Let’s build the first LinearSVC to predict if a flower is an Iris setosa.

from verticapy.machine_learning.vertica import LinearSVC
from verticapy.machine_learning.model_selection import cross_validate

predictors = ["PetalLengthCm", "ratio_swl"]
response = "Species_Iris-setosa"
model = LinearSVC("svc_setosa_iris")
cross_validate(model, iris, predictors, response)
...
csi
time
1-fold...1.017.181851625442505
2-fold...1.015.774991989135742
3-fold...1.013.243692636489868
avg...1.015.400178750356039
std...0.01.629445259086767

Our model is excellent. Let’s build it using the entire dataset.

model.fit(iris, predictors, response)


=======
details
=======
  predictor  |coefficient
-------------+-----------
  Intercept  | -0.23704  
petallengthcm| -0.54910  
  ratio_swl  |  3.13800  


===========
call_string
===========
SELECT svm_classifier('public.svc_setosa_iris', '"public"."_verticapy_tmp_view_v_mldb_c772779097b711efa8720242ac120002_"', '"species_iris-setosa"', '"PetalLengthCm", "ratio_swl"'
USING PARAMETERS class_weights='1,1', C=1, max_iterations=100, intercept_mode='regularized', intercept_scaling=1, epsilon=0.0001);

===============
Additional Info
===============
       Name       |Value
------------------+-----
accepted_row_count| 250 
rejected_row_count|  0  
 iteration_count  |  8  

Let’s plot the model to see the perfect separation.

model.plot()

We can add this probability to the vDataFrame.

model.predict_proba(iris, name = "setosa", pos_label = 1)
123
SepalLengthCm
Numeric(5,2)
100%
...
123
ratio_swl
Numeric(22)
100%
123
setosa
Float(22)
100%
14.6...0.7826086956521740.841533100572887
24.7...0.6808510638297870.76595900739171
34.7...0.6808510638297870.73514805993585
44.8...0.6250.722212112179584
54.8...0.6458333333333330.713207858194324
64.8...0.7083333333333330.719586013677281
74.9...0.6122448979591840.714111143515526
84.9...0.632653061224490.715971528918452
94.9...0.632653061224490.715971528918452
104.9...0.632653061224490.715971528918452
115.0...0.460.353061615330462
125.0...0.680.745193749016457
135.1...0.6862745098039220.759098004217551
145.4...0.5555555555555560.275942083881882
155.4...0.629629629629630.714038231013369
165.4...0.7222222222222220.788424580584295
175.5...0.4363636363636360.289169426943208
185.5...0.4363636363636360.278014495678082
195.6...0.4821428571428570.263022398357408
205.7...0.5263157894736840.290758414906492

Let’s create a model to classify the Iris virginica.

predictors = [
    "PetalLengthCm",
    "SepalLengthCm",
    "SepalWidthCm",
    "PetalWidthCm",
    "ratio_pwl",
    "ratio_swl",
]
response = "Species_Iris-virginica"
model = LinearSVC("svc_virginica_iris")
cross_validate(model, iris, predictors, response)
...
csi
time
1-fold...0.965517241379310422.611406087875366
2-fold...0.970588235294117619.794111967086792
3-fold...0.97297297297297319.11236333847046
avg...0.969692816548800420.50596046447754
std...0.0031089456354509221.5145673206054286

We have another excellent model. Let’s add it to the vDataFrame.

model.fit(iris, predictors, response)
model.predict_proba(iris, name = "virginica", pos_label = 1)
123
SepalLengthCm
Numeric(5,2)
100%
...
123
SepalWidthCm
Numeric(5,2)
100%
123
virginica
Float(22)
100%
14.6...3.60.000455747290886906
24.7...3.20.00139140638971681
34.7...3.20.00251955766982754
44.8...3.00.00223640521351681
54.8...3.10.00279150100167775
64.8...3.40.00336592475065291
74.9...3.00.00207780291089906
84.9...3.10.00230024485969189
94.9...3.10.00230024485969189
104.9...3.10.00230024485969189
115.0...2.30.151843075577554
125.0...3.40.00143941431306228
135.1...3.50.00100133346021508
145.4...3.00.373732220700207
155.4...3.40.00116375600766135
165.4...3.90.000405239187610279
175.5...2.40.218651520531901
185.5...2.40.250781925000777
195.6...2.70.316586394528472
205.7...3.00.235240010162963

Let’s evaluate our final model (the combination of two LinearSVC).

iris.case_when(
    "prediction",
    iris["setosa"] > 0.5, "Iris-setosa",
    iris["virginica"] > 0.5, "Iris-virginica",
    "Iris-versicolor",
)
iris["score"] = (iris["Species"] == iris["prediction"])
iris["score"].avg()
Out[4]: 0.968

We have a great model with an accuracy of 96% on an entirely balanced dataset.

Conclusion

We’ve solved our problem in a Pandas-like way, all without ever loading data into memory!