When I finished my first machine learning lectures, I wanted a project that used everything I had learned: data loading, preprocessing, train-test split, scaling, training, and evaluation. So I built a small but complete project: predicting whether a customer will purchase a product, based on their age, salary, experience, and gender.

The dataset is tiny (8 customers), which makes it perfect for learning — you can follow every number by hand.

The data

Age Salary Experience Gender Purchase
25 500 2 Male 0
32 800 5 Female 1
45 1200 15 Male 1
22 400 1 Female 0
38 950 8 Male 1
28 600 3 Female 0
50 1500 20 Male 1
30 700 4 Female 1

Purchase is the target: 1 means the customer bought, 0 means they didn't. The rest are the features.

Step 1: Load the data and encode the categories

Models work with numbers, so the Gender column needs encoding: Male = 0, Female = 1.

import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score data = { 'Age': [25, 32, 45, 22, 38, 28, 50, 30], 'Salary': [500, 800, 1200, 400, 950, 600, 1500, 700], 'Experience': [2, 5, 15, 1, 8, 3, 20, 4], 'Gender': ['Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female'], 'Purchase': [0, 1, 1, 0, 1, 0, 1, 1] } df = pd.DataFrame(data) df['Gender'] = df['Gender'].map({'Male': 0, 'Female': 1}) 

Step 2: Split features and target, then train/test

X = df[['Age', 'Salary', 'Experience', 'Gender']] y = df['Purchase'] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) # Train shape: (6, 4) — Test shape: (2, 4) 

test_size=0.2 means 20% of the data goes to testing. random_state=42 makes the split reproducible.

Step 3: Scale the features

Age ranges up to 50, Salary up to 1500. Without scaling, the bigger numbers dominate the model. StandardScaler fixes that — and the key rule is: fit only on the training data, then transform both sets.

scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) # never fit_transform on test data! 

Step 4: Train and evaluate

Since the target is yes/no, this is a classification problem, and logistic regression is the natural first model:

model = LogisticRegression() model.fit(X_train, y_train) y_pred = model.predict(X_test) print("Actual: ", list(y_test)) # [0, 1] print("Predicted:", list(y_pred)) # [0, 1] print("Accuracy: ", accuracy_score(y_test, y_pred)) # 1.0 

The model predicted both test customers correctly: accuracy 1.0.

Step 5: Predict a new customer

Now the fun part — a brand-new customer: age 36, salary 950, 6 years of experience, female. The new data must go through the same scaler (transform, not fit):

new_customer = [[36, 950, 6, 1]] new_customer_scaled = scaler.transform(new_customer) prediction = model.predict(new_customer_scaled) print("Approved" if prediction[0] == 1 else "Not Approved") # Approved 

Result: Approved (Yes) — the model predicts this customer will purchase.

What I learned

  1. Preprocessing is half the project. Encoding categories and scaling features matter as much as the model itself.
  2. Never fit on test data. Fitting the scaler on test data leaks information and gives fake results.
  3. Small data teaches the pipeline. With 8 rows I could trace every step; the same pipeline scales to thousands of rows.
  4. Accuracy on 2 test samples is not proof. A 1.0 here is encouraging, not conclusive — real evaluation needs more data and more metrics (precision, recall, confusion matrix).

If you are learning ML, build this project yourself and change one thing at a time: try a different random_state, add a feature, or compare logistic regression with a decision tree. That is where the real learning happens.