Loading...

Iris

This example uses the iris dataset to predict the species of various flowers based on their physical features.

  • 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 vastorbit:

import vastorbit as vo

vo.__version__

Connect to VAST. This example uses an existing connection called VASTDSN . 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.

vo.connect("VASTDSN")

Let’s create a VastFrame of the dataset.

from vastorbit.datasets import load_iris

iris = load_iris()
iris.head(5)
123
sepallengthcm
Decimal(5,2)
100%
123
sepalwidthcm
Decimal(5,2)
100%
123
petallengthcm
Decimal(5,2)
100%
123
petalwidthcm
Decimal(5,2)
100%
Abc
species
Varchar(30)
100%
15.13.51.40.2Iris-setosa
24.93.01.40.2Iris-setosa
34.73.21.30.2Iris-setosa
44.63.11.50.2Iris-setosa
55.03.61.40.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)
dtypecounttoptop_percentunique
"sepallengthcm"decimal(5,2)1505.06.66735.0
"sepalwidthcm"decimal(5,2)1503.017.33323.0
"petallengthcm"decimal(5,2)1501.59.33343.0
"petalwidthcm"decimal(5,2)1500.218.66722.0
"species"varchar(30)150Iris-virginica33.3333.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 vastorbit.machine_learning.vast import LinearSVC
from vastorbit.machine_learning.model_selection import cross_validate

predictors = ["PetalLengthCm", "ratio_swl"]
response = "Species_Iris-setosa"
model = LinearSVC("svc_setosa_iris", max_iter = 1000)
cross_validate(model, iris, predictors, response)
aucprc_aucaccuracylog_lossprecisionrecallf1_scoremccinformednessmarkednesscsitime
1-fold1.00.175714285714285821.00.19481761376816351.01.01.01.01.01.01.00.39058709144592285
2-fold1.00.173878205128205071.00.174029976227587621.01.01.01.01.01.01.00.5655460357666016
3-fold1.00.18811274509803921.00.199788794575484621.01.01.01.01.01.01.00.3199501037597656
avg1.00.179235078646843381.00.189545461523745271.01.01.01.01.01.01.00.42536107699076336
std0.00.0063220523668432150.00.011157235996913460.00.00.00.00.00.00.00.10323521042609826

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

model.fit(iris, predictors, response)

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

model.plot()

We can add this probability to the VastFrame.

model.predict_proba(iris, name = "setosa", pos_label = 1)
123
sepallengthcm
Decimal(5,2)
100%
123
sepalwidthcm
Decimal(5,2)
100%
123
petallengthcm
Decimal(5,2)
100%
123
petalwidthcm
Decimal(5,2)
100%
Abc
species
Varchar(30)
100%
123
species_Iris-setosa
Bool
100%
123
species_Iris-versicolor
Bool
100%
123
species_Iris-virginica
Bool
100%
123
ratio_pwl
Decimal(13,8)
100%
123
ratio_swl
Decimal(13,8)
100%
123
setosa
Double
100%
15.13.51.40.2Iris-setosa1000.142857140.686274510.7533862310328937
24.93.01.40.2Iris-setosa1000.142857140.61224490.7347100983001176
34.73.21.30.2Iris-setosa1000.153846150.680851060.7673806330944822
44.63.11.50.2Iris-setosa1000.133333330.673913040.7342632994790236
55.03.61.40.2Iris-setosa1000.142857140.720.761595468695358
65.43.91.70.4Iris-setosa1000.235294120.722222220.7134820101455942
74.63.41.40.3Iris-setosa1000.214285710.739130430.7661678386279932
85.03.41.50.2Iris-setosa1000.133333330.680.7358342158526154
94.42.91.40.2Iris-setosa1000.142857140.659090910.7466324281606391
104.93.11.50.1Iris-setosa1000.066666670.632653060.7234590908839088
115.43.71.50.2Iris-setosa1000.133333330.685185190.737167699846424
124.83.41.60.2Iris-setosa1000.1250.708333330.7267037644243937
134.83.01.40.1Iris-setosa1000.071428570.6250.7379915215420295
144.33.01.10.1Iris-setosa1000.090909090.697674420.7996161340009732
155.84.01.20.2Iris-setosa1000.166666670.689655170.7840216084848081
165.74.41.50.4Iris-setosa1000.266666670.771929820.7588254032478668
175.43.91.30.4Iris-setosa1000.307692310.722222220.7770233333481225
185.13.51.40.3Iris-setosa1000.214285710.686274510.7533862310328937
195.73.81.70.3Iris-setosa1000.176470590.666666670.6981988028179743
205.13.81.50.3Iris-setosa1000.20.745098040.7522584560908878

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", max_iter = 1000)
cross_validate(model, iris, predictors, response)
aucprc_aucaccuracylog_lossprecisionrecallf1_scoremccinformednessmarkednesscsitime
1-fold1.00.242727272727272681.00.200657430015383661.01.01.01.01.01.01.00.3792917728424072
2-fold1.00.22423245614035080.95833333333333340.2399256952961951.00.89473684210526320.94444444444444440.9148835360580520.89473684210526330.9354838709677420.89473684210526320.14366984367370605
3-fold0.99663299663299660.210430760998356450.94117647058823530.237696054832244180.94117647058823530.88888888888888880.91428571428571430.87038827977848920.85858585858585860.88235294117647060.84210526315789470.30555009841918945
avg0.99887766554433220.225796829955326660.96650326797385620.226093060047940940.98039215686274520.92787524366471740.95291005291005290.92842393861218040.91777423356370720.93927893738140420.9122807017543860.2761705716451009
std0.00158722060872400530.0132313168036730810.0246997000944950560.0180087253021874450.0277296776935901070.0510557538156288450.035501028988817480.053773019137176240.0599862812198583150.048104119776929910.065643112048665660.09840999549977007

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

model.fit(iris, predictors, response)
model.predict_proba(iris, name = "virginica", pos_label = 1)
123
sepallengthcm
Decimal(5,2)
100%
123
sepalwidthcm
Decimal(5,2)
100%
123
petallengthcm
Decimal(5,2)
100%
123
petalwidthcm
Decimal(5,2)
100%
Abc
species
Varchar(30)
100%
123
species_Iris-setosa
Bool
100%
123
species_Iris-versicolor
Bool
100%
123
species_Iris-virginica
Bool
100%
123
ratio_pwl
Decimal(13,8)
100%
123
ratio_swl
Decimal(13,8)
100%
123
setosa
Double
100%
123
virginica
Double
100%
15.13.51.40.2Iris-setosa1000.142857140.686274510.75338623103289370.0007296201703394868
24.93.01.40.2Iris-setosa1000.142857140.61224490.73471009830011760.0014058511173605517
34.73.21.30.2Iris-setosa1000.153846150.680851060.76738063309448220.0011623041879743321
44.63.11.50.2Iris-setosa1000.133333330.673913040.73426329947902360.0018303349093362288
55.03.61.40.2Iris-setosa1000.142857140.720.7615954686953580.0007114409374903144
65.43.91.70.4Iris-setosa1000.235294120.722222220.71348201014559420.0008412646621078331
74.63.41.40.3Iris-setosa1000.214285710.739130430.76616783862799320.001396973628006954
85.03.41.50.2Iris-setosa1000.133333330.680.73583421585261540.0009996800043388435
94.42.91.40.2Iris-setosa1000.142857140.659090910.74663242816063910.002270472963791192
104.93.11.50.1Iris-setosa1000.066666670.632653060.72345909088390880.0012246022779389021
115.43.71.50.2Iris-setosa1000.133333330.685185190.7371676998464240.0005461931729756654
124.83.41.60.2Iris-setosa1000.1250.708333330.72670376442439370.0013341977091354206
134.83.01.40.1Iris-setosa1000.071428570.6250.73799152154202950.0012741245386073093
144.33.01.10.1Iris-setosa1000.090909090.697674420.79961613400097320.0012243303583175569
155.84.01.20.2Iris-setosa1000.166666670.689655170.78402160848480810.00019672232223855336
165.74.41.50.4Iris-setosa1000.266666670.771929820.75882540324786680.0003086020837643312
175.43.91.30.4Iris-setosa1000.307692310.722222220.77702333334812250.00047993869640503033
185.13.51.40.3Iris-setosa1000.214285710.686274510.75338623103289370.000868941342595363
195.73.81.70.3Iris-setosa1000.176470590.666666670.69819880281797430.0006185188604478436
205.13.81.50.3Iris-setosa1000.20.745098040.75225845609088780.000739172518255419

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()

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!