Siksha Sarovar

Siksha Sarovar (sikshasarovar.com) is a free educational web application that helps students in India learn programming and prepare for academic and competitive exams. The platform offers structured coding courses (C, C++, Python, Java, HTML, CSS, PHP, Power BI, AI, Machine Learning, Data Science), complete university curriculum notes for BCA/MCA students with previous year question papers, Class 10 and Class 12 CBSE/HBSE school notes, and dedicated preparation material for SSC, UPSC, Banking, Railway and other government exams. Browsing the site is completely free and requires no account. Users may optionally sign in with Google solely to save their learning progress, quiz scores and personal preferences across devices.

Privacy Policy | Terms of Service | Contact Siksha Sarovar | About Siksha Sarovar

v4.0.9 · PWA
Siksha Sarovar logo
Siksha Sarovar
Your Learning Universe

Siksha Sarovar is a free e-learning platform for coding courses, BCA university notes and competitive exam preparation. Optional Google sign-in saves your learning progress across devices.

Initializing knowledge base…
Compiling modules 0%

Unit 1 — Data Preprocessing

Lesson 11 of 46 in the free Introduction to Data Analytics notes on Siksha Sarovar, written by Rohit Jangra.

Data Preprocessing

Data preprocessing is the broader stage that converts raw data into a form suitable for analysis and modelling. Data cleaning is one component of it; the full set of tasks is usually stated as four (some books say five):

Why Preprocess?

Problem in raw dataEffect if not handled
Incomplete (missing attribute values)Algorithms crash or silently drop rows
Noisy (errors, outliers)Model learns the noise, not the pattern
Inconsistent (conflicting codes/names)Same entity counted as two
Redundant (duplicate columns/rows)Multicollinearity, inflated importance
Different scales (age 0–100 vs income 0–10⁷)Distance-based models (KNN, K-Means) dominated by the big-scale feature
Categorical textMost algorithms only accept numbers
Too many featuresCurse of dimensionality, overfitting, slow training

1. Data Cleaning

Covered in the previous lesson — missing values, noise/outliers, duplicates, and inconsistencies.

Noise-smoothing techniques worth naming in an exam:

TechniqueHow it works
BinningSort values, partition into bins, then smooth by bin mean / bin median / bin boundaries
RegressionFit a function to the data and use fitted values
ClusteringGroup similar values; points outside all clusters are noise
Moving averageSmooth a time series with a rolling window
# Smoothing by BIN MEANS — classic textbook example
data = [4, 8, 15, 21, 21, 24, 25, 28, 34]
bin_size = 3
smoothed = []
for i in range(0, len(data), bin_size):
    chunk = data[i:i + bin_size]
    mean = sum(chunk) / len(chunk)
    smoothed.extend([round(mean, 1)] * len(chunk))

print("Original:", data)
print("Bin means:", smoothed)
# Original: [4, 8, 15, 21, 21, 24, 25, 28, 34]
# Bin means: [9.0, 9.0, 9.0, 22.0, 22.0, 22.0, 29.0, 29.0, 29.0]

# Smoothing by BIN BOUNDARIES — replace each value with the nearer boundary
smoothed_b = []
for i in range(0, len(data), bin_size):
    chunk = data[i:i + bin_size]
    lo, hi = min(chunk), max(chunk)
    smoothed_b.extend([lo if abs(v - lo) <= abs(v - hi) else hi for v in chunk])
print("Bin boundaries:", smoothed_b)
# Bin boundaries: [4, 4, 15, 21, 21, 24, 25, 25, 34]

2. Data Integration

Combining data from multiple sources — databases, files, APIs — into a single coherent store.

Problems to solve during integration:

ProblemDescriptionExample
Entity identificationDo two records refer to the same real-world entity?cust_id in CRM vs customer_number in billing
Schema integrationMatching attribute names and meaningsdob vs birth_date
RedundancyAttribute derivable from others, or duplicatedannual_salary and monthly_salary
Value conflictsSame attribute, different representation/unitPrice in ₹ vs \$; weight in kg vs lb
Duplicate tuplesSame row appearing from two sourcesSame order in two exports

Detecting redundancy — correlation analysis for numeric attributes, chi-square test for categorical ones. Highly correlated attributes carry duplicate information; keep one.

import pandas as pd

students = pd.DataFrame({"roll": [1, 2, 3], "name": ["Riya", "Zoya", "Kabir"]})
marks    = pd.DataFrame({"roll": [1, 2, 4], "marks": [88, 76, 65]})

inner = pd.merge(students, marks, on="roll", how="inner")   # only matching rolls
left  = pd.merge(students, marks, on="roll", how="left")    # all students
outer = pd.merge(students, marks, on="roll", how="outer")   # everything
print(left)
#    roll   name  marks
# 0     1   Riya   88.0
# 1     2   Zoya   76.0
# 2     3  Kabir    NaN     <- integration created a new missing value

# Redundancy check
df = pd.DataFrame({"monthly": [30000, 45000, 52000], "annual": [360000, 540000, 624000]})
print(df.corr().round(3))
# correlation = 1.000  ->  perfectly redundant, drop one column

3. Data Reduction

Producing a smaller representation of the dataset that yields (almost) the same analytical results.

MethodTypeIdea
Feature selectionDimensionalityKeep the most informative subset of original attributes; discard irrelevant/redundant ones
PCA (Principal Component Analysis)DimensionalityProject data onto a few new axes (principal components) capturing maximum variance
SamplingNumerosityAnalyse a representative subset of rows
AggregationNumerosityRoll daily data up to monthly totals
ClusteringNumerosityReplace a group of rows by its cluster representative
Data cube aggregationNumerosityPre-computed multidimensional summaries (OLAP)
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import numpy as np

X = np.array([[2.5, 2.4, 1.1], [0.5, 0.7, 0.3], [2.2, 2.9, 1.5],
              [1.9, 2.2, 1.0], [3.1, 3.0, 1.6], [2.3, 2.7, 1.2]])

X_scaled = StandardScaler().fit_transform(X)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

print("Explained variance ratio:", pca.explained_variance_ratio_.round(3))
# e.g. [0.955 0.036]  ->  2 components retain ~99% of the information from 3 features
print("Reduced shape:", X_pca.shape)   # (6, 2)
# Aggregation — numerosity reduction on a time series
daily = pd.DataFrame({
    "date": pd.date_range("2026-01-01", periods=90),
    "sales": np.random.randint(800, 2200, 90),
})
monthly = daily.set_index("date").resample("ME")["sales"].sum()
print(monthly)      # 90 rows reduced to 3, trend preserved

4. Data Transformation

Converting data into forms appropriate for mining — normalization, standardization, encoding, aggregation, and attribute construction. Covered fully in the next lesson.

5. Data Discretization

Converting continuous attributes into a finite set of intervals/labels.

MethodDescriptionExample
Equal-width binningDivide the range into k intervals of equal sizeAges 0–20, 21–40, 41–60
Equal-frequency binningEach bin holds (roughly) the same number of recordsQuartile-based income bands
Clustering-basedBins found by K-Means on the attributeData-driven groupings
Entropy/decision-tree basedSplits chosen to maximise class purity (supervised)Optimal cut-points for a classifier
Concept hierarchyDomain hierarchy of increasing abstractionStreet → City → State → Country
ages = pd.Series([12, 19, 23, 27, 34, 41, 45, 52, 63, 71])

# Equal-width: three bins of equal age range
print(pd.cut(ages, bins=3).value_counts().sort_index())

# Equal-frequency: three bins with equal counts
print(pd.qcut(ages, q=3).value_counts().sort_index())

# Custom, domain-driven bins with labels
groups = pd.cut(ages, bins=[0, 18, 35, 60, 100],
                labels=["Minor", "Young Adult", "Middle Aged", "Senior"])
print(pd.DataFrame({"age": ages, "group": groups}))

End-to-End Preprocessing Pipeline

import pandas as pd, numpy as np
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

df = pd.DataFrame({
    "age":     [19, np.nan, 21, 20, 22],
    "income":  [25000, 42000, np.nan, 31000, 58000],
    "city":    ["Delhi", "Noida", "Delhi", np.nan, "Noida"],
})

numeric_features = ["age", "income"]
categorical_features = ["city"]

numeric_pipe = Pipeline([
    ("impute", SimpleImputer(strategy="median")),
    ("scale", StandardScaler()),
])
categorical_pipe = Pipeline([
    ("impute", SimpleImputer(strategy="most_frequent")),
    ("encode", OneHotEncoder(handle_unknown="ignore")),
])

preprocessor = ColumnTransformer([
    ("num", numeric_pipe, numeric_features),
    ("cat", categorical_pipe, categorical_features),
])

processed = preprocessor.fit_transform(df)
print(processed.shape)     # (5, 4)  ->  2 scaled numeric + 2 one-hot city columns

Building preprocessing as a pipeline rather than ad-hoc steps is what makes it reproducible — the same object can be re-applied to new data in production, guaranteeing training and inference see identical treatment.