---
title: "Train your first machine learning model in 20 lines of Python"
description: "No maths degree required. Load data, split it, fit a model, check the score — the four steps every scikit-learn project uses, explained line by line."
url: https://articles.sythra.ai/articles/first-machine-learning-model-scikit-learn
slug: first-machine-learning-model-scikit-learn
author: "vaibhavkothari"
author_url: https://articles.sythra.ai/writers/vaibhavkothari
date_published: 2026-08-26T08:34:22.039Z
date_modified: 2026-08-29T10:29:25.265Z
topics: ["Python", "Machine Learning", "Learning"]
reading_time_minutes: 6
publisher: "Sythra"
publisher_url: https://sythra.ai
access: free
language: en
---

# Train your first machine learning model in 20 lines of Python

> No maths degree required. Load data, split it, fit a model, check the score — the four steps every scikit-learn project uses, explained line by line.

Source: https://articles.sythra.ai/articles/first-machine-learning-model-scikit-learn · Author: vaibhavkothari · Published: 2026-08-26 · Reading time: 6 min · Topics: Python, Machine Learning, Learning

Every machine learning project — recommendation engines, fraud detection, your first homework assignment — follows the same four steps:

1. Load data
2. Split it into training and testing parts
3. Fit a model on the training part
4. Score it on the testing part

That is it. The rest is detail. Here is the whole thing in twenty lines, then an explanation of every one.

## What you need

```bash
python -m pip install scikit-learn pandas
```

## The 20 lines

```python
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

data = load_wine()
X, y = data.data, data.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

model = RandomForestClassifier(n_estimators=200, random_state=42)
model.fit(X_train, y_train)

predictions = model.predict(X_test)
print("Accuracy:", accuracy_score(y_test, predictions))
```

Run it. You should see accuracy around 0.97. You just trained a model that identifies which of three vineyards a wine came from, using its chemical measurements.

## Step 1 — Understand X and y

```python
X, y = data.data, data.target
```

`X` holds the features — alcohol content, colour intensity, magnesium, and ten more measurements. Each row is one wine.

`y` holds the labels — which vineyard, as 0, 1 or 2.

Capital `X` and lowercase `y` is a convention worth keeping: `X` is a table (many rows, many columns), `y` is a single column.

Look at the actual shape before doing anything else:

```python
print("Features:", X.shape)          # (178, 13)
print("Labels:", y.shape)            # (178,)
print("Feature names:", data.feature_names[:5])
print("Classes:", data.target_names)
```

178 wines, 13 measurements each. Small, clean, perfect for learning.

## Step 2 — Split before you look

```python
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
```

Three arguments matter:

- **`test_size=0.2`** — keep 20% aside. The model never sees it during training.
- **`random_state=42`** — makes the split reproducible. Without it you get different numbers every run and cannot tell whether a change helped.
- **`stratify=y`** — keeps the class proportions the same in both parts. Skip it on imbalanced data and your test set may be missing an entire class.

Why hold data back at all? Because a model that has seen an answer can simply repeat it. Testing on training data measures memory, not learning. More on the ways this goes wrong in [train/test split and data leakage](https://articles.sythra.ai/articles/train-test-split-data-leakage).

## Step 3 — Fit the model

```python
model = RandomForestClassifier(n_estimators=200, random_state=42)
model.fit(X_train, y_train)
```

A random forest builds 200 decision trees, each on a slightly different slice of the data, then takes a majority vote. It is the best default for tabular data: it handles different scales, ignores useless columns, and rarely needs tuning.

`fit` is where learning happens. Every scikit-learn model has the same three methods:

| Method | Does |
|---|---|
| `.fit(X, y)` | Learn from the data |
| `.predict(X)` | Guess labels for new rows |
| `.score(X, y)` | Return accuracy in one call |

Learn those three and you can drive any of the hundred-plus models in the library.

## Step 4 — Score honestly

```python
predictions = model.predict(X_test)
print("Accuracy:", accuracy_score(y_test, predictions))
```

Accuracy is the fraction of test rows predicted correctly. It is a fine starting metric — but only when your classes are roughly balanced. On data that is 99% one class, a model that always guesses that class scores 99% and is useless. That is why [precision and recall](https://articles.sythra.ai/articles/confusion-matrix-precision-recall-explained) exist.

Always ask what a lazy baseline would score:

```python
from sklearn.dummy import DummyClassifier

baseline = DummyClassifier(strategy="most_frequent").fit(X_train, y_train)
print("Baseline:", baseline.score(X_test, y_test))
```

If your fancy model barely beats the dummy, it has learned nothing.

## Step 5 — See what the model learned

Random forests can tell you which measurements mattered:

```python
import pandas as pd

importance = pd.Series(
    model.feature_importances_, index=data.feature_names
).sort_values(ascending=False)

print(importance.head(5))
```

Usually `proline`, `flavanoids` and `color_intensity` dominate. This one line often teaches you more about your problem than the accuracy score does — and it is how you spot a leaked column, where one feature has suspiciously high importance because it secretly contains the answer.

## Step 6 — Use it on your own CSV

The same four steps, with a real file:

```python
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

df = pd.read_csv("my_data.csv")
df = df.dropna()

y = df["target"]
X = pd.get_dummies(df.drop(columns=["target"]), drop_first=True)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

model = RandomForestClassifier(n_estimators=200, random_state=42)
model.fit(X_train, y_train)
print("Accuracy:", model.score(X_test, y_test))
```

Two additions handle real data: `dropna()` removes rows with holes, and `get_dummies` turns text categories into numeric columns. If either raises an error, the fixes are in [could not convert string to float](https://articles.sythra.ai/articles/could-not-convert-string-to-float-fix).

## Step 7 — Save and reload the model

```python
import joblib

joblib.dump(model, "wine_model.joblib")

loaded = joblib.load("wine_model.joblib")
print(loaded.predict(X_test[:3]))
```

Training is slow, prediction is fast. Save once, load anywhere — this is exactly how models get into web apps.

## Common problems (and fixes)

| Problem | Fix |
|---|---|
| `could not convert string to float` | Encode text columns with `pd.get_dummies` |
| `Input contains NaN` | `df.dropna()` or `SimpleImputer` |
| 100% accuracy | Suspect leakage — a column contains the answer |
| Accuracy near chance | Check that `X` and `y` rows still line up |
| Different result every run | Set `random_state` everywhere |

## What you learned

- The four-step shape of every scikit-learn project
- What `X` and `y` mean and why the split happens first
- `fit`, `predict`, `score` — the interface of every model
- Why a dummy baseline is required context for any score
- How feature importance shows what the model actually used

```remember
# Remember this
`X` -> the inputs, one row per example
`y` -> the answer you want predicted
`fit` / `predict` / `score` -> the interface of every scikit-learn model
---
Split **before** anything else, and always compare against a dummy
baseline — a score with no baseline means nothing.
```


## FAQ

### How do I train my first machine learning model in Python?

Load a dataset into `X` (features) and `y` (labels), split with `train_test_split`, call `.fit(X_train, y_train)` on a model such as `RandomForestClassifier`, then measure `.score(X_test, y_test)` on the held-out data.

### What do X and y mean in scikit-learn?

`X` is the table of input features, one row per example. `y` is the single column of answers you want to predict. The capital letter marks a two-dimensional table and lowercase a one-dimensional column.

### Which model should a beginner start with?

`RandomForestClassifier` for tabular data. It works without scaling, tolerates irrelevant columns, and gives strong results with default settings.

### Why do I need train_test_split?

A model can memorise data it has already seen, so scoring on training data measures memory rather than learning. Holding 20% back gives you an honest estimate of performance on new data.

### What accuracy is good enough?

It depends entirely on your baseline. Compare against `DummyClassifier` — if your model barely beats always-guess-the-most-common-class, it has not learned anything useful.

## Next reading on Sythra Articles

- [Train/test split and the accuracy lie](https://articles.sythra.ai/articles/train-test-split-data-leakage)
- [Confusion matrix, precision and recall explained](https://articles.sythra.ai/articles/confusion-matrix-precision-recall-explained)
- [Stop memorizing Python syntax](https://articles.sythra.ai/articles/seven-python-patterns-for-ml-notebooks)

## Glossary (terms defined in this article)
- **features** (basic) — The input columns the model learns from
- **labels** (basic) — The answer you want the model to predict
- **random forest** (medium) — Many small decision trees voting together on the answer
