ML Project ยท Mobile Price Classification Dataset

Mobile Price
Classification: Predict
Phone Price Ranges.

Dive into the Mobile Price Classification dataset on Kaggle. We’ll train two machine-learning models โ€” Logistic Regression and Random Forest โ€” on 2,000 phones with 20 hardware features to predict one of 4 price ranges (Low / Medium / High / Very High). Every line of code is explained for beginners โ€” with copy buttons on every block.

๐Ÿ“ฑ2,000 Phones
๐Ÿ“Š20 Features
๐ŸŽฏ4 Price Ranges
๐Ÿค–2 ML Models
mobile_price.py
# Mobile Price Classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
acc = accuracy_score(y_test, rf.predict(X_test))
2,000 Phones20 hardware features
Random Forest100 decision trees
Confusion Matrixvisualize accuracy
Step 01 / Data Loading

Load the dataset with KaggleHub.

Stream the Mobile Price Classification dataset straight into a pandas DataFrame โ€” no manual download needed.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” KaggleHub

What is this dataset? The Mobile Price Classification dataset contains 2,000 fictional phones described by 20 hardware features โ€” battery power, RAM, screen size, pixel resolution, number of cores, Wi-Fi, Bluetooth, and so on. The target column price_range has four classes: 0 (Low Cost), 1 (Medium Cost), 2 (High Cost), 3 (Very High Cost). Your model’s job is to learn which feature combination maps to which class.

What is KaggleHub? Kaggle is a website where people share datasets for machine learning. KaggleHub is a Python library that lets you load those datasets directly into your code with one line โ€” no manual download, no manual CSV path.

Important: The file_path is the CSV filename inside the dataset. Visit the Kaggle dataset page โ†’ Files tab to confirm. For this dataset, the file with the target column is train.csv.

step1_load_data.py
# Install dependencies as needed: # pip install kagglehub[pandas-datasets] pandas numpy matplotlib seaborn scikit-learn import kagglehub from kagglehub import KaggleDatasetAdapter import pandas as pd # Set the path to the file you'd like to load # For this dataset, the labeled file is train.csv file_path = "train.csv" # Load the latest version df = kagglehub.load_dataset( KaggleDatasetAdapter.PANDAS, "iabhishekofficial/mobile-price-classification", file_path, ) print("Shape:", df.shape) print("First 5 records:", df.head())
โžœ~/mobile-pricepython step1_load_data.py
Shape: (2000, 21) First 5 records: battery_power blue clock_speed dual_sim fc four_g int_memory … ram sc_h sc_w talk_time three_g touch_screen wifi price_range 0 842 0 2.2 0 1 0 7 … 2549 17 3 13 0 0 1 1 1 1021 1 0.5 1 0 1 53 … 2631 16 8 3 1 1 0 2 2 1937 1 2.8 1 2 1 21 … 2769 8 2 7 1 1 1 2 … โ† 2000 rows ร— 21 columns (20 features + 1 target)
โœ“Dataset loaded successfully
Step 02 / Exploration

Explore the data with Pandas & Seaborn.

Before training, we need to understand the data: how many phones per price class, which features correlate with price, and how RAM separates the categories.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” EDA (Exploratory Data Analysis)

Why explore first? If you train a model blindly, you might feed it garbage. EDA answers three questions: Is the data balanced? (same number of samples per class), Which features matter? (high correlation with target), and Are there patterns? (e.g., higher RAM โ†’ higher price).

What is a correlation heatmap? A grid where each cell shows how strongly two columns move together. Values range from -1 (opposite) to +1 (same direction). In this dataset, you’ll see ram glow bright red next to price_range โ€” that’s the strongest signal in the entire dataset.

What is a boxplot? A boxplot shows the distribution of a numeric column grouped by a category. The box represents the middle 50% of values, the line inside is the median, and the “whiskers” extend to typical min/max. We’ll use it to see RAM distribution per price class โ€” the boxes will rise like a staircase from class 0 to class 3.

step2_explore.py
import matplotlib.pyplot as plt import seaborn as sns # Quick numeric summary (mean, min, max, std for every column) print(df.describe()) # Is the target balanced? 500 in each class is perfect print("\nTarget distribution:\n", df['price_range'].value_counts()) # Correlation heatmap โ€” find the strongest signals plt.figure(figsize=(12, 10)) sns.heatmap(df.corr(), cmap='coolwarm', annot=False) plt.title('Feature Correlation Heatmap') plt.show() # Boxplot of RAM per price range โ€” expect a clear staircase plt.figure(figsize=(8, 5)) sns.boxplot(x='price_range', y='ram', data=df) plt.title('RAM Distribution by Price Range') plt.show()
โžœ~/mobile-pricepython step2_explore.py
battery_power blue clock_speed … wifi price_range count 2000.00000 2000 2000.000000 … 2000 2000.000000 mean 1238.51850 0.5 1.522250 … 0.5 1.500000 std 439.41834 0.5 0.815974 … 0.5 1.118314 min 501.00000 0.0 0.500000 … 0.0 0.000000 max 1998.00000 1.0 3.000000 … 1.0 3.000000 Target distribution: price_range 1 500 2 500 0 500 3 500 Name: count, dtype: int64 โ† 2 matplotlib windows pop up: heatmap + RAM boxplot
โœ“Data explored โ€” RAM clearly dominates the price signal
Step 03 / Preprocessing

Split & scale with scikit-learn.

Before training, we separate the features (X) from the target (y), hold out 20% of the data for testing, and scale features for the linear model.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Splitting & Scaling

Why separate X and y? The model needs to learn a rule: “given these features, predict this target”. We put all input columns into X and the column we want to predict (price_range) into y. The .drop() method removes price_range from X so the model can’t “cheat” by seeing the answer.

Why train/test split? If we train and test on the same data, the model can just memorize. We split 80% for training and 20% for testing. The model only sees the training portion. We then check its accuracy on the unseen 20% โ€” this simulates how it would perform on real-world new phones. The stratify=y argument keeps the four price classes balanced in both splits.

Why scale features? Logistic Regression uses gradient descent, which is sensitive to feature magnitudes. battery_power ranges from 500 to 2000, while wifi is just 0 or 1 โ€” the larger numbers would dominate. StandardScaler transforms every column to have mean 0 and standard deviation 1, putting all features on equal footing. We fit_transform on the training set and only transform on the test set (never fit on test data โ€” that would leak information).

step3_preprocess.py
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # Features (X) = all 20 hardware columns # Target (y) = price_range (0/1/2/3) X = df.drop('price_range', axis=1) y = df['price_range'] # 80% training, 20% testing โ€” stratify keeps 4 classes balanced X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # Standardize features for Logistic Regression scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) print("Training set:", X_train.shape) print("Test set:", X_test.shape)
โžœ~/mobile-pricepython step3_preprocess.py
Training set: (1600, 20) Test set: (400, 20) โ† X_train_scaled and X_test_scaled are ready for the linear model
โœ“Features split and scaled successfully
Step 04 / Model Training

Train Logistic Regression & Random Forest.

We’ll train two scikit-learn classifiers on the same data so we can compare them. Different algorithms have different strengths, and seeing both is the best way to learn.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Two Classifiers

Logistic Regression is a linear model. It draws straight decision boundaries between the four price classes. It’s fast, interpretable, and works best when the relationship between features and target is roughly linear. It needs scaled features because it uses gradient descent โ€” large numbers like battery_power would otherwise dwarf binary flags like wifi. We feed it X_train_scaled.

Random Forest is an ensemble model. It builds 100 decision trees (n_estimators=100), each on a random subset of the data, and lets them vote. The majority prediction wins. This makes it powerful for non-linear patterns and resistant to overfitting. Trees split on raw feature thresholds, so scaling isn’t required โ€” we feed it X_train directly. The random_state=42 argument makes the result reproducible.

Why train both? Logistic Regression gives you a clean baseline. If Random Forest is dramatically better, that tells you the relationship between features and price is non-linear. If they’re similar, the problem is mostly linear. Comparing them is one of the most educational things you can do as a beginner.

step4_train.py
from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier # --- Model 1: Logistic Regression (needs scaled features) --- lr = LogisticRegression(max_iter=1000) lr.fit(X_train_scaled, y_train) # --- Model 2: Random Forest (tree-based, no scaling needed) --- rf = RandomForestClassifier(n_estimators=100, random_state=42) rf.fit(X_train, y_train) print("Logistic Regression trained on", X_train_scaled.shape[0], "samples") print("Random Forest uses", rf.n_estimators, "trees")
โžœ~/mobile-pricepython step4_train.py
Logistic Regression trained on 1600 samples Random Forest uses 100 trees โ† both models are now fitted and ready to predict
โœ“Both classifiers trained successfully
Step 05 / Evaluation

Evaluate with confusion matrix & feature importance.

Training is only half the job. We now compare the two models on the unseen 20% test set and visualize where they shine โ€” and where they get confused.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Evaluation Metrics

Accuracy is the simplest metric: the percentage of phones the model classified correctly. For this dataset, both models usually score between 85% and 97% โ€” Logistic Regression often edges out Random Forest here because the relationship between RAM and price is largely linear.

Confusion Matrix is a 4ร—4 grid (we have 4 classes). Rows = actual class, columns = predicted class. The diagonal cells show correct predictions. Off-diagonal cells show mistakes. A bright diagonal with dim off-diagonals = a good model. In our heatmap, you’ll likely see a few phones from class 1 mistakenly predicted as class 2 โ€” that’s the boundary where Medium and High Cost overlap.

Classification Report gives three numbers per class: precision (out of all phones predicted as “High”, how many were actually High?), recall (out of all actually-High phones, how many did we find?), and f1-score (a balance of the two). The support column shows how many true samples each class has in the test set.

Feature Importance is a Random Forest superpower. After training, the model tells you which features it actually used most often when splitting. We’ll plot the top 10 โ€” expect ram to dominate, with battery_power, px_width, and px_height following.

step5_evaluate.py
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report import matplotlib.pyplot as plt import seaborn as sns # Predict on the unseen test set lr_pred = lr.predict(X_test_scaled) rf_pred = rf.predict(X_test) # Compare accuracy print("Logistic Regression Accuracy:", accuracy_score(y_test, lr_pred)) print("Random Forest Accuracy:", accuracy_score(y_test, rf_pred)) # Detailed per-class report print("\nClassification Report (Random Forest):\n", classification_report(y_test, rf_pred)) # Confusion matrix heatmap cm = confusion_matrix(y_test, rf_pred) plt.figure(figsize=(7, 5)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['Low', 'Medium', 'High', 'Very High'], yticklabels=['Low', 'Medium', 'High', 'Very High']) plt.xlabel('Predicted') plt.ylabel('Actual') plt.title('Random Forest Confusion Matrix') plt.show() # Top 10 most important features importances = pd.Series( rf.feature_importances_, index=X.columns ).sort_values(ascending=False)[:10] plt.figure(figsize=(8, 5)) sns.barplot(x=importances.values, y=importances.index, palette='viridis') plt.title('Top 10 Most Important Features') plt.show()
โžœ~/mobile-pricepython step5_evaluate.py
Logistic Regression Accuracy: 0.9575 Random Forest Accuracy: 0.8750 Classification Report (Random Forest): precision recall f1-score support 0 0.90 0.92 0.91 100 1 0.83 0.81 0.82 100 2 0.84 0.83 0.83 100 3 0.93 0.94 0.93 100 accuracy 0.88 400 macro avg 0.87 0.88 0.87 400 โ† 2 plots pop up: confusion matrix + top-10 feature bar chart
โœ“Models evaluated โ€” Logistic Regression wins on this dataset
Step 06 / Prediction

Predict a new phone & wrap up.

The final test: can our trained model predict the price range for a phone it has never seen? Let’s give it a single new phone spec and see what it says.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Predicting New Data

How to predict for one phone? Build a one-row DataFrame with the exact same 20 columns the model was trained on. Then call rf.predict(new_phone) โ€” the model returns a single integer (0, 1, 2, or 3) representing the predicted price class. We map it to a human-readable label like “High Cost”.

Which model to use? Since Logistic Regression scored higher in step 5, we’d technically use lr.predict() with scaled input for production. But for the demo we use Random Forest because it doesn’t need a scaler โ€” the same new_phone DataFrame can be passed directly. If you wanted to use Logistic Regression, you’d just run scaler.transform(new_phone) first.

The phone we’ll predict: A mid-range phone with 1500 mAh battery, 2.5 GB RAM, 8 MP camera, 16 GB storage, 1400ร—800 screen. The model should predict class 1 or 2 โ€” let’s see.

step6_predict.py
# Define a brand-new phone with all 20 features new_phone = pd.DataFrame([{ 'battery_power': 1500, 'blue': 1, 'clock_speed': 1.8, 'dual_sim': 1, 'fc': 4, 'four_g': 1, 'int_memory': 16, 'm_dep': 0.5, 'mobile_wt': 140, 'n_cores': 4, 'pc': 8, 'px_height': 800, 'px_width': 1400, 'ram': 2500, 'sc_h': 12, 'sc_w': 6, 'talk_time': 14, 'three_g': 1, 'touch_screen': 1, 'wifi': 1 }]) # Predict with Random Forest (no scaling needed) predicted = rf.predict(new_phone)[0] # Map the integer class to a human-readable label labels = {0: 'Low Cost', 1: 'Medium Cost', 2: 'High Cost', 3: 'Very High Cost'} print(f"Predicted price range: {labels[predicted]}") print(f"RAM = 2500 MB, Battery = 1500 mAh")
โžœ~/mobile-pricepython step6_predict.py
Predicted price range: High Cost RAM = 2500 MB, Battery = 1500 mAh
โœ“New phone classified as High Cost (class 2)
๐ŸŽฏ What You Learned

By completing this project, you’ve built a complete supervised machine-learning pipeline โ€” the same shape used in real production systems:

  • Data Loading with kagglehub โ€” pulling a Kaggle dataset straight into a DataFrame.
  • Exploratory Data Analysis with pandas & seaborn โ€” describing, balancing, and visualizing the dataset.
  • Preprocessing with train_test_split & StandardScaler โ€” splitting, stratifying, and standardizing features.
  • Model Training with LogisticRegression & RandomForestClassifier โ€” comparing a linear baseline against an ensemble.
  • Evaluation with accuracy_score, confusion_matrix, classification_report โ€” measuring precision, recall, and feature importance.
  • Inference on a brand-new data point โ€” turning a one-row DataFrame into a price-range label.

Happy coding, Love you, my lovely developers! ๐Ÿ’™

๐Ÿš€ Ideas to extend the project

  • Try more classifiers: SVC, KNeighborsClassifier, GradientBoostingClassifier, or XGBoost and rank them all.
  • Hyperparameter tuning with GridSearchCV โ€” find the best n_estimators, max_depth, and min_samples_split for Random Forest.
  • Drop the obvious features (RAM is too dominant) and see how much accuracy falls โ€” a great lesson in feature dependence.
  • Build a Streamlit web app where users pick phone specs in a form and get a live price prediction.
  • Use test.csv from the same Kaggle dataset as a real submission set and write predictions to a CSV file.
08 / FAQ

Frequently Asked Questions

What ML algorithms are used in this mobile price classification project? +

This project trains and compares two classifiers from scikit-learn: Logistic Regression (a fast, linear model that needs scaled features) and Random Forest (an ensemble of 100 decision trees that handles non-linear patterns without scaling). Both predict the price_range target with 4 classes: 0 (Low), 1 (Medium), 2 (High), 3 (Very High).

What features are most important for predicting mobile price? +

According to the Random Forest feature_importances_ attribute, RAM is by far the strongest predictor, followed by battery_power, pixel width, pixel height, and mobile weight. Together these five features usually account for over 70% of the model’s decision power โ€” which is why the EDA heatmap shows the brightest correlation cell at the intersection of ram and price_range.

Do I need to scale features for mobile price classification? +

Yes for Logistic Regression, because it uses gradient descent and is sensitive to the magnitude of features like RAM (in megabytes) versus dual_sim (0 or 1). Random Forest is tree-based and does not require scaling, but you should still split your data into train and test sets with stratify=y to keep the four price classes balanced.

Why does Logistic Regression often beat Random Forest here? +

The relationship between RAM and price_range in this dataset is mostly linear and well-separated. Random Forest shines when the decision boundary is non-linear or when features interact in complex ways. For this clean dataset, the linear model’s bias is actually an advantage โ€” it generalizes better and avoids the small over-fitting penalty trees can suffer.

Run the project
yourself.

Open a terminal, install the required libraries, and run the file end-to-end. Or click “Copy Full Project Code” at the top of this page.

2,000 phone records20 featuresLogistic + Random ForestFull source code
09 / Share

Share this Project

If you found this walkthrough helpful, share it with your friends and fellow developers!

Scroll to Top