A follow-up to last week's decision tree post, where sepal length and sepal width scored exactly 0% feature importance and petal measurements did all the work. The obvious next question: what does the correlation structure between all four measurements actually look like? One prompt answers it:
"From the iris data, show a correlation heatmap of all measurements."
The four measurements live in ML Demo 2, a bundle of ten classic ML datasets VerbaGPT ships as a public demo — in this case sitting in Azure SQL. Same question, unchanged, would have run identically against Postgres, MySQL, or Snowflake; the connector is swappable underneath the natural-language layer, the question isn't.
| Sepal Length | Sepal Width | Petal Length | Petal Width | |
|---|---|---|---|---|
| Sepal Length | 1.00 | −0.12 | 0.87 | 0.82 |
| Sepal Width | −0.12 | 1.00 | −0.43 | −0.37 |
| Petal Length | 0.87 | −0.43 | 1.00 | 0.96 |
| Petal Width | 0.82 | −0.37 | 0.96 | 1.00 |
Petal length and petal width correlate at 0.96 — about as close to redundant as two different physical measurements get. A model that has petal length gains almost nothing new from also having petal width. That alone explains why a decision tree could hit 97.78% accuracy using close to one effective petal signal, not two independent ones.
Sepal width is the outlier, and it goes the wrong way. It's the only measurement negatively correlated with all three others (−0.12, −0.43, −0.37). Sepal length, meanwhile, is positively correlated with both petal measurements (0.87, 0.82) — it's not useless, it's redundant, carrying much the same signal petal length already carries. Sepal width is the one truly distinct measurement in the dataset, and it's also the noisiest, weakest signal of the four. A tree splitting on gini impurity doesn't reward "different" — it rewards "cleanly separates the classes," and petals do that job alone.
Put together: the tree didn't skip sepal measurements because they're irrelevant to species. It skipped sepal length because petal length already captured its signal, and skipped sepal width because being the odd one out isn't the same as being predictive.
Under the hood, the question resolved in two separate model calls before a line of code ran: a schema-resolution pass that picked the right table and columns (gpt-oss-120b, OpenAI's open-weight model, hosted on Cerebras — 0.50s), then a code-generation pass that wrote the actual pandas/seaborn (Gemma 4 31b, Google's open-weight model, same Cerebras hardware). The generated code — a straight df.corr() and a seaborn.heatmap() call — executed against the live Azure SQL table in 332 milliseconds. Round trip, prompt to rendered chart: 5.6 seconds. Nothing here is a fixed pipeline; both the model doing the reasoning and the database underneath it are swappable independently of the question being asked.
Data source: Fisher's Iris dataset (1936) — 150 samples, 3 species, 4 features. Same table used in the decision tree post.
Ask your own question about this dataset → The ML Demo datasource is live and open — no signup required for a few questions.