Hyperparameter tuning with CrossValidator in Apache Spark - Time & Space Complexity
When tuning hyperparameters using CrossValidator in Apache Spark, we want to know how the time needed grows as we try more parameter combinations and use more data.
We ask: How does the total work increase when we add more data or try more settings?
Analyze the time complexity of the following code snippet.
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
from pyspark.ml.classification import LogisticRegression
lr = LogisticRegression()
paramGrid = ParamGridBuilder() \
.addGrid(lr.regParam, [0.1, 0.01]) \
.addGrid(lr.elasticNetParam, [0.0, 0.5, 1.0]) \
.build()
cv = CrossValidator(estimator=lr, estimatorParamMaps=paramGrid, evaluator=None, numFolds=3)
cvModel = cv.fit(trainingData)
This code tries different combinations of logistic regression settings and tests each with 3-fold cross-validation on the training data.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Training the model on each fold for every parameter combination.
- How many times: Number of parameter combinations multiplied by number of folds.
As we increase data size or try more parameter combinations, the total work grows proportionally.
| Input Size (n) | Approx. Operations |
|---|---|
| 10,000 rows, 6 params, 3 folds | Train model 18 times on 10,000 rows each |
| 100,000 rows, 6 params, 3 folds | Train model 18 times on 100,000 rows each |
| 100,000 rows, 12 params, 5 folds | Train model 60 times on 100,000 rows each |
Pattern observation: Doubling data doubles training time; doubling parameter combos or folds multiplies total training runs.
Time Complexity: O(p * f * n)
This means the time grows linearly with the number of parameter combinations (p), folds (f), and data size (n).
[X] Wrong: "CrossValidator runs the model only once regardless of parameters or folds."
[OK] Correct: Each parameter set and fold requires a separate model training, so total work multiplies by these counts.
Understanding this time complexity helps you explain how tuning choices affect training time, showing you grasp practical trade-offs in real projects.
"What if we increased the number of folds from 3 to 10? How would the time complexity change?"
Practice
CrossValidator in Apache Spark's machine learning pipeline?Solution
Step 1: Understand CrossValidator's role
CrossValidator splits data into training and validation sets multiple times to evaluate model performance.Step 2: Identify the purpose of hyperparameter tuning
It tests different hyperparameter combinations to find the best model settings.Final Answer:
To find the best hyperparameters by testing multiple data splits -> Option DQuick Check:
CrossValidator = Best hyperparameters [OK]
- Thinking CrossValidator trains on full data without validation
- Confusing CrossValidator with data cleaning tools
- Assuming CrossValidator is for visualization only
ParamGridBuilder in Spark ML?Solution
Step 1: Recall ParamGridBuilder syntax
ParamGridBuilder is instantiated, thenaddGridis called with parameter and list of values.Step 2: Check each option's syntax
paramGrid = ParamGridBuilder().addGrid(model.maxDepth, [2, 5]).build() correctly callsParamGridBuilder()thenaddGrid(model.maxDepth, [2, 5])and finallybuild().Final Answer:
paramGrid = ParamGridBuilder().addGrid(model.maxDepth, [2, 5]).build() -> Option AQuick Check:
ParamGridBuilder() + addGrid(param, values) + build() [OK]
- Calling addGrid without parentheses on ParamGridBuilder
- Using assignment inside addGrid instead of parameters
- Swapping parameter and values order in addGrid
cvModel.bestModel.getMaxDepth()?
from pyspark.ml.classification import DecisionTreeClassifier from pyspark.ml.tuning import CrossValidator, ParamGridBuilder from pyspark.ml.evaluation import BinaryClassificationEvaluator model = DecisionTreeClassifier() paramGrid = ParamGridBuilder().addGrid(model.maxDepth, [2, 4]).build() evaluator = BinaryClassificationEvaluator() cv = CrossValidator(estimator=model, estimatorParamMaps=paramGrid, evaluator=evaluator, numFolds=2) cvModel = cv.fit(trainingData) best_depth = cvModel.bestModel.getMaxDepth()
Solution
Step 1: Understand CrossValidator fitting
CrossValidator tries all parameter combinations and selects the best model based on evaluator metric.Step 2: Interpret bestModel.getMaxDepth()
The bestModel will have maxDepth set to the value that gave the best validation score, either 2 or 4.Final Answer:
2 or 4 depending on which depth gave better validation metric -> Option BQuick Check:
bestModel maxDepth = best param tested [OK]
- Assuming bestModel always uses first grid value
- Thinking getMaxDepth() method does not exist
- Calculating average of grid values instead of selecting best
from pyspark.ml.classification import LogisticRegression from pyspark.ml.tuning import CrossValidator, ParamGridBuilder from pyspark.ml.evaluation import BinaryClassificationEvaluator lr = LogisticRegression() paramGrid = ParamGridBuilder().addGrid(lr.regParam, [0.1, 0.01]) evaluator = BinaryClassificationEvaluator() cv = CrossValidator(estimator=lr, estimatorParamMaps=paramGrid, evaluator=evaluator, numFolds=3) cvModel = cv.fit(trainingData)
Solution
Step 1: Check ParamGridBuilder usage
ParamGridBuilder requires calling.build()to create the parameter grid list.Step 2: Identify missing method call
The code misses.build()afteraddGrid, soparamGridis not a valid parameter map list.Final Answer:
Missing .build() call after ParamGridBuilder() -> Option AQuick Check:
ParamGridBuilder().addGrid(...).build() required [OK]
- Forgetting to call .build() after addGrid
- Using wrong evaluator for classification
- Setting numFolds less than 2 (valid but uncommon)
numTrees with values [10, 20] and maxDepth with values [5, 10]. How many total models will CrossValidator train if numFolds=3?Solution
Step 1: Calculate total hyperparameter combinations
numTrees has 2 values, maxDepth has 2 values, so total combinations = 2 * 2 = 4.Step 2: Multiply by number of folds
CrossValidator trains each combination on each fold, so total models = 4 * 3 = 12.Step 3: Re-check calculation
Wait, the question asks how many total models trained. Each fold trains one model per combination, so total = combinations * folds = 4 * 3 = 12.Final Answer:
12 models -> Option CQuick Check:
Combinations * folds = 12 [OK]
- Multiplying number of values incorrectly
- Forgetting to multiply by number of folds
- Confusing total models with total parameter combos
Ready to prove it?
Pass the test and this pattern moves unknown
