November 22, 2025
17 min read

Senior Data Scientist Interview Questions: Complete Guide

interview
career-advice
job-search
Senior Data Scientist Interview Questions: Complete Guide
MB

Milad Bonakdar

Author

Master advanced data science concepts with essential interview questions covering advanced ML algorithms, deep learning, model deployment, feature engineering, A/B testing, and big data for senior data scientists.


Introduction

Senior data scientists are expected to architect end-to-end machine learning solutions, optimize model performance, deploy models to production, and communicate insights to stakeholders. This role demands deep expertise in advanced algorithms, feature engineering, model deployment, and the ability to solve complex business problems with data.

This comprehensive guide covers essential interview questions for Senior Data Scientists, spanning advanced machine learning, deep learning, feature engineering, model deployment, A/B testing, and big data technologies. Each question includes detailed answers, rarity assessment, and difficulty ratings.


Advanced Machine Learning (6 Questions)

1. Explain the bias-variance tradeoff.

Answer: The bias-variance tradeoff describes the relationship between model complexity and prediction error.

  • Bias: Error from oversimplifying assumptions (underfitting)
  • Variance: Error from sensitivity to training data fluctuations (overfitting)
  • Tradeoff: Decreasing bias increases variance and vice versa
  • Goal: Find optimal balance that minimizes total error
Loading diagram...
import numpy as np
from sklearn.model_selection import learning_curve
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt

# Generate data
X = np.random.rand(100, 1) * 10
y = 2 * X + 3 + np.random.randn(100, 1) * 2

# High bias model (max_depth=1)
high_bias = DecisionTreeRegressor(max_depth=1)

# High variance model (max_depth=20)
high_variance = DecisionTreeRegressor(max_depth=20)

# Optimal model (max_depth=3)
optimal = DecisionTreeRegressor(max_depth=3)

# Learning curves show bias-variance tradeoff
train_sizes, train_scores, val_scores = learning_curve(
    optimal, X, y.ravel(), cv=5, train_sizes=np.linspace(0.1, 1.0, 10)
)

print(f"Training score: {train_scores.mean():.2f}")
print(f"Validation score: {val_scores.mean():.2f}")

Rarity: Very Common Difficulty: Hard


2. What is regularization and explain L1 vs L2 regularization.

Answer: Regularization adds a penalty term to the loss function to prevent overfitting.

  • L1 (Lasso):
    • Penalty: Sum of absolute values of coefficients
    • Effect: Sparse models (some coefficients become exactly 0)
    • Use: Feature selection
  • L2 (Ridge):
    • Penalty: Sum of squared coefficients
    • Effect: Shrinks coefficients toward 0 (but not exactly 0)
    • Use: When all features are potentially relevant
  • Elastic Net: Combines L1 and L2
from sklearn.linear_model import Lasso, Ridge, ElasticNet
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
import numpy as np

# Generate data with many features
X, y = make_regression(n_samples=100, n_features=20, n_informative=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# L1 Regularization (Lasso)
lasso = Lasso(alpha=1.0)
lasso.fit(X_train, y_train)
print(f"Lasso coefficients: {np.sum(lasso.coef_ != 0)} non-zero out of {len(lasso.coef_)}")

# L2 Regularization (Ridge)
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
print(f"Ridge coefficients: {np.sum(ridge.coef_ != 0)} non-zero out of {len(ridge.coef_)}")

# Elastic Net (L1 + L2)
elastic = ElasticNet(alpha=1.0, l1_ratio=0.5)
elastic.fit(X_train, y_train)

print(f"\nLasso score: {lasso.score(X_test, y_test):.3f}")
print(f"Ridge score: {ridge.score(X_test, y_test):.3f}")
print(f"Elastic Net score: {elastic.score(X_test, y_test):.3f}")

Rarity: Very Common Difficulty: Medium


3. Explain ensemble methods: Bagging vs Boosting.

Answer: Ensemble methods combine multiple models to improve performance.

  • Bagging (Bootstrap Aggregating):
    • Train models in parallel on random subsets
    • Reduces variance
    • Example: Random Forest
  • Boosting:
    • Train models sequentially, each correcting previous errors
    • Reduces bias
    • Examples: AdaBoost, Gradient Boosting, XGBoost
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score

# Load data
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.3, random_state=42
)

# Bagging - Random Forest
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
rf_score = rf.score(X_test, y_test)

# Boosting - Gradient Boosting
gb = GradientBoostingClassifier(n_estimators=100, random_state=42)
gb.fit(X_train, y_train)
gb_score = gb.score(X_test, y_test)

print(f"Random Forest (Bagging) accuracy: {rf_score:.3f}")
print(f"Gradient Boosting accuracy: {gb_score:.3f}")

# Cross-validation
rf_cv = cross_val_score(rf, data.data, data.target, cv=5)
gb_cv = cross_val_score(gb, data.data, data.target, cv=5)

print(f"\nRF CV scores: {rf_cv.mean():.3f} (+/- {rf_cv.std():.3f})")
print(f"GB CV scores: {gb_cv.mean():.3f} (+/- {gb_cv.std():.3f})")

Rarity: Very Common Difficulty: Hard


4. What is cross-validation and why is k-fold better than train-test split?

Answer: Cross-validation evaluates model performance more robustly than a single train-test split.

  • K-Fold CV:
    • Splits data into k folds
    • Trains k times, each time using different fold as validation
    • Averages results
  • Benefits:
    • More reliable performance estimate
    • Uses all data for both training and validation
    • Reduces variance in performance estimate
  • Variations: Stratified K-Fold, Leave-One-Out, Time Series Split
from sklearn.model_selection import cross_val_score, KFold, StratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris

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

model = LogisticRegression(max_iter=200)

# Standard K-Fold
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kfold)
print(f"K-Fold CV scores: {scores}")
print(f"Mean: {scores.mean():.3f} (+/- {scores.std():.3f})")

# Stratified K-Fold (preserves class distribution)
stratified_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
stratified_scores = cross_val_score(model, X, y, cv=stratified_kfold)
print(f"\nStratified K-Fold scores: {stratified_scores}")
print(f"Mean: {stratified_scores.mean():.3f} (+/- {stratified_scores.std():.3f})")

# Custom cross-validation
from sklearn.model_selection import cross_validate

cv_results = cross_validate(
    model, X, y, cv=5,
    scoring=['accuracy', 'precision_macro', 'recall_macro'],
    return_train_score=True
)

print(f"\nTest accuracy: {cv_results['test_accuracy'].mean():.3f}")
print(f"Test precision: {cv_results['test_precision_macro'].mean():.3f}")
print(f"Test recall: {cv_results['test_recall_macro'].mean():.3f}")

Rarity: Very Common Difficulty: Medium


5. Explain dimensionality reduction techniques (PCA, t-SNE).

Answer: Dimensionality reduction reduces the number of features while preserving information.

  • PCA (Principal Component Analysis):
    • Linear transformation
    • Finds directions of maximum variance
    • Preserves global structure
    • Fast, interpretable
  • t-SNE (t-Distributed Stochastic Neighbor Embedding):
    • Non-linear transformation
    • Preserves local structure
    • Good for visualization
    • Slower, not for feature extraction
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt

# Load high-dimensional data
digits = load_digits()
X, y = digits.data, digits.target

print(f"Original shape: {X.shape}")

# PCA - reduce to 2 dimensions
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
print(f"PCA shape: {X_pca.shape}")
print(f"Explained variance ratio: {pca.explained_variance_ratio_}")
print(f"Total variance explained: {pca.explained_variance_ratio_.sum():.3f}")

# t-SNE - reduce to 2 dimensions
tsne = TSNE(n_components=2, random_state=42)
X_tsne = tsne.fit_transform(X)
print(f"t-SNE shape: {X_tsne.shape}")

# PCA for feature extraction (keep 95% variance)
pca_95 = PCA(n_components=0.95)
X_reduced = pca_95.fit_transform(X)
print(f"\nComponents for 95% variance: {pca_95.n_components_}")
print(f"Reduced shape: {X_reduced.shape}")

Rarity: Common Difficulty: Hard


6. What is the ROC curve and AUC? When would you use it?

Answer: ROC (Receiver Operating Characteristic) curve plots True Positive Rate vs False Positive Rate at various thresholds.

  • AUC (Area Under Curve): Single metric summarizing ROC
    • AUC = 1.0: Perfect classifier
    • AUC = 0.5: Random classifier
    • AUC < 0.5: Worse than random
  • Use Cases:
    • Comparing models
    • Imbalanced datasets
    • When you need to choose threshold
from sklearn.metrics import roc_curve, roc_auc_score, auc
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
import matplotlib.pyplot as plt

# Load data
data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.3, random_state=42
)

# Train model
model = LogisticRegression(max_iter=10000)
model.fit(X_train, y_train)

# Get probability predictions
y_pred_proba = model.predict_proba(X_test)[:, 1]

# Calculate ROC curve
fpr, tpr, thresholds = roc_curve(y_test, y_pred_proba)
roc_auc = auc(fpr, tpr)

print(f"AUC: {roc_auc:.3f}")

# Alternative: direct AUC calculation
auc_score = roc_auc_score(y_test, y_pred_proba)
print(f"AUC (direct): {auc_score:.3f}")

# Find optimal threshold (Youden's J statistic)
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
print(f"Optimal threshold: {optimal_threshold:.3f}")

Rarity: Very Common Difficulty: Medium


Feature Engineering (4 Questions)

7. What techniques do you use for feature engineering?

Answer: Feature engineering creates new features from existing data to improve model performance.

  • Techniques:
    • Encoding: One-hot, label, target encoding
    • Scaling: StandardScaler, MinMaxScaler
    • Binning: Discretize continuous variables
    • Polynomial Features: Interaction terms
    • Domain-Specific: Date features, text features
    • Aggregations: Group statistics
from sklearn.preprocessing import StandardScaler, OneHotEncoder, PolynomialFeatures
import pandas as pd
import numpy as np

# Sample data
df = pd.DataFrame({
    'age': [25, 30, 35, 40, 45],
    'salary': [50000, 60000, 75000, 80000, 90000],
    'department': ['IT', 'HR', 'IT', 'Finance', 'HR'],
    'date': pd.date_range('2023-01-01', periods=5)
})

# One-hot encoding
df_encoded = pd.get_dummies(df, columns=['department'], prefix='dept')

# Scaling
scaler = StandardScaler()
df_encoded[['age_scaled', 'salary_scaled']] = scaler.fit_transform(
    df_encoded[['age', 'salary']]
)

# Binning
df_encoded['age_group'] = pd.cut(df['age'], bins=[0, 30, 40, 100], labels=['young', 'mid', 'senior'])

# Date features
df_encoded['year'] = df['date'].dt.year
df_encoded['month'] = df['date'].dt.month
df_encoded['day_of_week'] = df['date'].dt.dayofweek

# Polynomial features
poly = PolynomialFeatures(degree=2, include_bias=False)
poly_features = poly.fit_transform(df[['age', 'salary']])

# Interaction features
df_encoded['age_salary_interaction'] = df['age'] * df['salary']

print(df_encoded.head())

Rarity: Very Common Difficulty: Medium


8. How do you handle imbalanced datasets?

Answer: Imbalanced datasets have unequal class distributions, which can bias models.

  • Techniques:
    • Resampling:
      • Oversampling minority class (SMOTE)
      • Undersampling majority class
    • Class Weights: Penalize misclassification of minority class
    • Ensemble Methods: Balanced Random Forest
    • Evaluation: Use precision, recall, F1, not just accuracy
    • Anomaly Detection: Treat minority as anomaly
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler

# Create imbalanced dataset
X, y = make_classification(
    n_samples=1000, n_features=20, n_informative=15,
    n_classes=2, weights=[0.9, 0.1], random_state=42
)

print(f"Class distribution: {np.bincount(y)}")

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

# 1. Without handling imbalance
model_baseline = LogisticRegression()
model_baseline.fit(X_train, y_train)
y_pred_baseline = model_baseline.predict(X_test)
print("\nBaseline (no handling):")
print(classification_report(y_test, y_pred_baseline))

# 2. SMOTE (Synthetic Minority Over-sampling)
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
print(f"\nAfter SMOTE: {np.bincount(y_train_smote)}")

model_smote = LogisticRegression()
model_smote.fit(X_train_smote, y_train_smote)
y_pred_smote = model_smote.predict(X_test)
print("\nWith SMOTE:")
print(classification_report(y_test, y_pred_smote))

# 3. Class weights
model_weighted = LogisticRegression(class_weight='balanced')
model_weighted.fit(X_train, y_train)
y_pred_weighted = model_weighted.predict(X_test)
print("\nWith class weights:")
print(classification_report(y_test, y_pred_weighted))

Rarity: Very Common Difficulty: Medium


9. Explain feature selection techniques.

Answer: Feature selection identifies the most relevant features for modeling.

  • Methods:
    • Filter Methods: Statistical tests (correlation, chi-square)
    • Wrapper Methods: Recursive Feature Elimination (RFE)
    • Embedded Methods: Lasso, tree-based feature importance
    • Dimensionality Reduction: PCA (different from selection)
from sklearn.feature_selection import SelectKBest, chi2, RFE, SelectFromModel
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import MinMaxScaler

# Load data
data = load_breast_cancer()
X, y = data.data, data.target

# 1. Filter Method - SelectKBest with chi-square
X_scaled = MinMaxScaler().fit_transform(X)
selector_chi2 = SelectKBest(chi2, k=10)
X_chi2 = selector_chi2.fit_transform(X_scaled, y)
print(f"Original features: {X.shape[1]}")
print(f"Selected features (chi2): {X_chi2.shape[1]}")

# 2. Wrapper Method - Recursive Feature Elimination
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rfe = RFE(estimator=rf, n_features_to_select=10)
X_rfe = rfe.fit_transform(X, y)
print(f"Selected features (RFE): {X_rfe.shape[1]}")
print(f"Feature ranking: {rfe.ranking_}")

# 3. Embedded Method - Tree-based feature importance
rf.fit(X, y)
importances = rf.feature_importances_
indices = np.argsort(importances)[::-1]

print("\nTop 10 features by importance:")
for i in range(10):
    print(f"{i+1}. {data.feature_names[indices[i]]}: {importances[indices[i]]:.4f}")

# SelectFromModel
selector_model = SelectFromModel(rf, threshold='median', prefit=True)
X_selected = selector_model.transform(X)
print(f"\nSelected features (importance): {X_selected.shape[1]}")

Rarity: Common Difficulty: Medium


10. How do you handle categorical variables with high cardinality?

Answer: High cardinality categorical variables have many unique values.

  • Techniques:
    • Target Encoding: Replace with target mean
    • Frequency Encoding: Replace with frequency
    • Embedding: Learn dense representations (neural networks)
    • Grouping: Combine rare categories into "Other"
    • Hashing: Hash to fixed number of buckets
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# Sample data with high cardinality
df = pd.DataFrame({
    'city': np.random.choice([f'City_{i}' for i in range(100)], 1000),
    'target': np.random.randint(0, 2, 1000)
})

print(f"Unique cities: {df['city'].nunique()}")

# 1. Target Encoding
target_means = df.groupby('city')['target'].mean()
df['city_target_encoded'] = df['city'].map(target_means)

# 2. Frequency Encoding
freq = df['city'].value_counts()
df['city_frequency'] = df['city'].map(freq)

# 3. Grouping rare categories
freq_threshold = 10
rare_cities = freq[freq < freq_threshold].index
df['city_grouped'] = df['city'].apply(lambda x: 'Other' if x in rare_cities else x)

print(f"\nAfter grouping: {df['city_grouped'].nunique()} unique values")

# 4. Hash encoding (using category_encoders library)
# from category_encoders import HashingEncoder
# encoder = HashingEncoder(cols=['city'], n_components=10)
# df_hashed = encoder.fit_transform(df)

print(df[['city', 'city_target_encoded', 'city_frequency', 'city_grouped']].head())

Rarity: Common Difficulty: Hard


Model Deployment & Production (4 Questions)

11. How do you deploy a machine learning model to production?

Answer: Model deployment makes models available for real-world use.

  • Steps:
    1. Model Serialization: Save model (pickle, joblib, ONNX)
    2. API Development: Create REST API (Flask, FastAPI)
    3. Containerization: Docker for consistency
    4. Deployment: Cloud platforms (AWS, GCP, Azure)
    5. Monitoring: Track performance, drift
    6. CI/CD: Automated testing and deployment
# 1. Train and save model
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
import joblib

# Train model
data = load_iris()
model = RandomForestClassifier()
model.fit(data.data, data.target)

# Save model
joblib.dump(model, 'model.joblib')

# 2. Create API with FastAPI
from fastapi import FastAPI
import numpy as np

app = FastAPI()

# Load model
model = joblib.load('model.joblib')

@app.post("/predict")
def predict(features: list):
    # Convert to numpy array
    X = np.array(features).reshape(1, -1)
    prediction = model.predict(X)
    probability = model.predict_proba(X)
    
    return {
        "prediction": int(prediction[0]),
        "probability": probability[0].tolist()
    }

# 3. Dockerfile
"""
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
"""

# 4. Usage
# curl -X POST "http://localhost:8000/predict" \
#      -H "Content-Type: application/json" \
#      -d '{"features": [5.1, 3.5, 1.4, 0.2]}'

Rarity: Very Common Difficulty: Hard


12. What is model monitoring and why is it important?

Answer: Model monitoring tracks model performance in production.

  • What to Monitor:
    • Performance Metrics: Accuracy, precision, recall
    • Data Drift: Input distribution changes
    • Concept Drift: Target relationship changes
    • System Metrics: Latency, throughput, errors
  • Actions:
    • Alerts when performance degrades
    • Retrain with new data
    • A/B testing new models
import numpy as np
from scipy import stats

# Simulate production data
training_data = np.random.normal(0, 1, 1000)
production_data = np.random.normal(0.5, 1.2, 1000)  # Drifted

# Detect data drift using Kolmogorov-Smirnov test
statistic, p_value = stats.ks_2samp(training_data, production_data)

print(f"KS Statistic: {statistic:.4f}")
print(f"P-value: {p_value:.4f}")

if p_value < 0.05:
    print("Data drift detected! Consider retraining the model.")
else:
    print("No significant drift detected.")

# Monitor model performance
class ModelMonitor:
    def __init__(self, model):
        self.model = model
        self.predictions = []
        self.actuals = []
        
    def log_prediction(self, X, y_pred, y_true=None):
        self.predictions.append(y_pred)
        if y_true is not None:
            self.actuals.append(y_true)
    
    def get_accuracy(self):
        if len(self.actuals) == 0:
            return None
        return np.mean(np.array(self.predictions) == np.array(self.actuals))
    
    def check_drift(self, new_data, reference_data):
        statistic, p_value = stats.ks_2samp(new_data, reference_data)
        return p_value < 0.05

# Usage
monitor = ModelMonitor(model)
# monitor.log_prediction(X, y_pred, y_true)
# accuracy = monitor.get_accuracy()

Rarity: Common Difficulty: Medium


13. Explain A/B testing in the context of machine learning.

Answer: A/B testing compares two versions (control vs treatment) to determine which performs better.

  • Process:
    1. Split traffic randomly
    2. Serve different models to each group
    3. Collect metrics
    4. Statistical test to determine winner
  • Metrics: Conversion rate, revenue, engagement
  • Statistical Tests: t-test, chi-square, Bayesian methods
import numpy as np
from scipy import stats

# Simulate A/B test results
# Control group (Model A)
control_conversions = 520
control_visitors = 10000

# Treatment group (Model B)
treatment_conversions = 580
treatment_visitors = 10000

# Calculate conversion rates
control_rate = control_conversions / control_visitors
treatment_rate = treatment_conversions / treatment_visitors

print(f"Control conversion rate: {control_rate:.4f}")
print(f"Treatment conversion rate: {treatment_rate:.4f}")
print(f"Lift: {((treatment_rate - control_rate) / control_rate * 100):.2f}%")

# Statistical significance test (two-proportion z-test)
pooled_rate = (control_conversions + treatment_conversions) / (control_visitors + treatment_visitors)
se = np.sqrt(pooled_rate * (1 - pooled_rate) * (1/control_visitors + 1/treatment_visitors))
z_score = (treatment_rate - control_rate) / se
p_value = 2 * (1 - stats.norm.cdf(abs(z_score)))

print(f"\nZ-score: {z_score:.4f}")
print(f"P-value: {p_value:.4f}")

if p_value < 0.05:
    print("Result is statistically significant!")
    if treatment_rate > control_rate:
        print("Treatment (Model B) is better.")
    else:
        print("Control (Model A) is better.")
else:
    print("No statistically significant difference.")

# Sample size calculation
from statsmodels.stats.power import zt_ind_solve_power

required_sample = zt_ind_solve_power(
    effect_size=0.02,  # Minimum detectable effect
    alpha=0.05,
    power=0.8,
    alternative='two-sided'
)
print(f"\nRequired sample size per group: {int(required_sample)}")

Rarity: Common Difficulty: Hard


14. What is MLOps and why is it important?

Answer: MLOps (Machine Learning Operations) applies DevOps principles to ML systems.

  • Components:
    • Version Control: Code, data, models
    • Automated Testing: Unit, integration, model tests
    • CI/CD Pipelines: Automated deployment
    • Monitoring: Performance, drift detection
    • Reproducibility: Experiment tracking
  • Tools: MLflow, Kubeflow, DVC, Weights & Biases
# Example: MLflow for experiment tracking
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Load data
data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.3, random_state=42
)

# Start MLflow run
with mlflow.start_run():
    # Log parameters
    n_estimators = 100
    max_depth = 5
    mlflow.log_param("n_estimators", n_estimators)
    mlflow.log_param("max_depth", max_depth)
    
    # Train model
    model = RandomForestClassifier(
        n_estimators=n_estimators,
        max_depth=max_depth,
        random_state=42
    )
    model.fit(X_train, y_train)
    
    # Evaluate
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    
    # Log metrics
    mlflow.log_metric("accuracy", accuracy)
    
    # Log model
    mlflow.sklearn.log_model(model, "random_forest_model")
    
    print(f"Accuracy: {accuracy:.3f}")
    print(f"Run ID: {mlflow.active_run().info.run_id}")

# Version control with DVC
"""
# Initialize DVC
dvc init

# Track data
dvc add data/train.csv
git add data/train.csv.dvc .gitignore
git commit -m "Add training data"

# Track model
dvc add models/model.pkl
git add models/model.pkl.dvc
git commit -m "Add trained model"
"""

Rarity: Common Difficulty: Hard


Deep Learning & Advanced Topics (4 Questions)

15. Explain the architecture of a neural network.

Answer: Neural networks consist of layers of interconnected neurons.

  • Components:
    • Input Layer: Receives features
    • Hidden Layers: Learn representations
    • Output Layer: Produces predictions
    • Activation Functions: ReLU, Sigmoid, Tanh
    • Weights & Biases: Learned parameters
import tensorflow as tf
from tensorflow import keras
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# Load data
digits = load_digits()
X, y = digits.data, digits.target

# Preprocess
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.3, random_state=42
)

# Build neural network
model = keras.Sequential([
    keras.layers.Dense(128, activation='relu', input_shape=(64,)),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation='softmax')
])

# Compile
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# Train
history = model.fit(
    X_train, y_train,
    epochs=50,
    batch_size=32,
    validation_split=0.2,
    verbose=0
)

# Evaluate
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"Test accuracy: {test_acc:.3f}")

# Model summary
model.summary()

Rarity: Common Difficulty: Medium


16. What is transfer learning and when would you use it?

Answer: Transfer learning uses pre-trained models as starting points for new tasks.

  • Benefits:
    • Faster training
    • Better performance with less data
    • Leverages learned features
  • Approaches:
    • Feature Extraction: Freeze pre-trained layers
    • Fine-tuning: Retrain some layers
  • Use Cases: Image classification, NLP, limited data
from tensorflow.keras.applications import VGG16
from tensorflow.keras import layers, models

# Load pre-trained model (without top classification layer)
base_model = VGG16(
    weights='imagenet',
    include_top=False,
    input_shape=(224, 224, 3)
)

# Freeze base model layers
base_model.trainable = False

# Add custom classification layers
model = models.Sequential([
    base_model,
    layers.GlobalAveragePooling2D(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(10, activation='softmax')  # 10 classes
])

model.compile(
    optimizer='adam',
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

print(f"Trainable parameters: {sum([tf.size(w).numpy() for w in model.trainable_weights])}")
print(f"Non-trainable parameters: {sum([tf.size(w).numpy() for w in model.non_trainable_weights])}")

# Fine-tuning: Unfreeze some layers
base_model.trainable = True
for layer in base_model.layers[:-4]:
    layer.trainable = False

model.compile(
    optimizer=tf.keras.optimizers.Adam(1e-5),  # Lower learning rate
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

Rarity: Common Difficulty: Medium


17. Explain gradient descent and its variants.

Answer: Gradient descent is an optimization algorithm that minimizes the loss function.

  • Variants:
    • Batch GD: Uses entire dataset (slow, stable)
    • Stochastic GD: Uses one sample (fast, noisy)
    • Mini-batch GD: Uses small batches (balanced)
    • Adam: Adaptive learning rates (most popular)
    • RMSprop, AdaGrad: Other adaptive methods
import numpy as np
import matplotlib.pyplot as plt

# Simple gradient descent implementation
def gradient_descent(X, y, learning_rate=0.01, epochs=1000):
    m, n = X.shape
    theta = np.zeros(n)
    losses = []
    
    for epoch in range(epochs):
        # Predictions
        predictions = X.dot(theta)
        
        # Loss (MSE)
        loss = np.mean((predictions - y) ** 2)
        losses.append(loss)
        
        # Gradient
        gradient = (2/m) * X.T.dot(predictions - y)
        
        # Update parameters
        theta -= learning_rate * gradient
    
    return theta, losses

# Generate data
np.random.seed(42)
X = np.random.rand(100, 1)
y = 2 * X.squeeze() + 1 + np.random.randn(100) * 0.1

# Add bias term
X_b = np.c_[np.ones((100, 1)), X]

# Run gradient descent
theta, losses = gradient_descent(X_b, y, learning_rate=0.1, epochs=1000)

print(f"Learned parameters: {theta}")
print(f"Final loss: {losses[-1]:.4f}")

# Compare with different learning rates
for lr in [0.001, 0.01, 0.1]:
    _, losses_lr = gradient_descent(X_b, y, learning_rate=lr, epochs=1000)
    print(f"LR={lr}: Final loss = {losses_lr[-1]:.4f}")

Rarity: Common Difficulty: Hard


18. What is the difference between batch normalization and dropout?

Answer: Both are regularization techniques but work differently.

  • Batch Normalization:
    • Normalizes inputs to each layer
    • Reduces internal covariate shift
    • Allows higher learning rates
    • Used during training and inference
  • Dropout:
    • Randomly drops neurons during training
    • Prevents co-adaptation of neurons
    • Only used during training
    • Acts as ensemble method
from tensorflow import keras
from tensorflow.keras import layers

# Model with Batch Normalization
model_bn = keras.Sequential([
    layers.Dense(128, input_shape=(784,)),
    layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.Dense(64),
    layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.Dense(10, activation='softmax')
])

# Model with Dropout
model_dropout = keras.Sequential([
    layers.Dense(128, activation='relu', input_shape=(784,)),
    layers.Dropout(0.5),
    layers.Dense(64, activation='relu'),
    layers.Dropout(0.3),
    layers.Dense(10, activation='softmax')
])

# Model with both
model_both = keras.Sequential([
    layers.Dense(128, input_shape=(784,)),
    layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.Dropout(0.3),
    layers.Dense(64),
    layers.BatchNormalization(),
    layers.Activation('relu'),
    layers.Dropout(0.2),
    layers.Dense(10, activation='softmax')
])

# Compile
for model in [model_bn, model_dropout, model_both]:
    model.compile(
        optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )

print("Batch Normalization model:")
model_bn.summary()

Rarity: Common Difficulty: Medium


Related Posts

Recent Posts

Weekly career tips that actually work

Get the latest insights delivered straight to your inbox