SpotOptim supports factor variables for optimizing categorical hyperparameters, such as activation functions, optimizers, or any discrete string-based choices. Factor variables are automatically converted between string values (external interface) and integers (internal optimization), making categorical optimization seamless.
6.1 Overview
What are Factor Variables?
Factor variables allow you to specify categorical choices as tuples of strings in the bounds. SpotOptim handles the conversion:
# Example: Accessing factor variable results as strings# (This assumes you've run an optimization with activation as a factor variable)# If you have a result from the previous examples:# best_activation = result.x[3] # For 4-parameter optimization# Or for simpler cases:# best_activation = result.x[0] # For single-parameter optimization# Example with inline optimization:from spotoptim import SpotOptimimport numpy as npdef quick_test(X): results = []for params in X: activation = params[0] score = {"ReLU": 3500, "Tanh": 3600}.get(activation, 4000) results.append(score + np.random.normal(0, 50))return np.array(results)opt = SpotOptim( fun=quick_test, bounds=[("ReLU", "Tanh")], var_type=["factor"], max_iter=10, seed=42)result = opt.optimize()# Access as string - this is the correct waybest_activation = result.x[0] # String value like "ReLU"print(f"Best activation: {best_activation} (type: {type(best_activation).__name__})")# You can use it directly in your model# model = LinearRegressor(activation=best_activation)
Best activation: ReLU (type: str)
✅ Mix factor variables with numeric/integer variables
# Wrong: Use strings, not integersbounds=[(0, 1, 2)] # Wrong!bounds=[("ReLU", "Sigmoid", "Tanh")] # Correct!
❌ Don’t expect integers in objective function
def objective(X): activation = X[0][2]# activation is a string, not an integer!# Don't do: if activation == 0: # Wrong!# Do: if activation == "ReLU": # Correct!
❌ Don’t manually convert factor variables
# SpotOptim handles conversion automatically# Don't do manual mapping in your objective function
❌ Don’t use empty tuples
# Wrong: Empty tuplebounds=[()]# Correct: At least one stringbounds=[("ReLU",)] # Single choice (will be treated as fixed)
6.9 Troubleshooting
6.9.1 Common Issues
Issue: Objective function receives integers instead of strings
Solution: Ensure you’re using the latest version of SpotOptim with factor variable support. Factor variables are automatically converted before calling the objective function.
Issue: ValueError: could not convert string to float
Solution: This occurs if there’s a version mismatch. Update SpotOptim to ensure the object array conversion is implemented correctly.
Issue: Results show integers instead of strings
Solution: Check that you’re accessing result.x (mapped values) instead of internal arrays. The result object automatically maps factor variables to their original strings.
Issue: Single-level factor variables cause dimension reduction
Behavior: If a factor variable has only one choice, e.g., ("ReLU",), SpotOptim treats it as a fixed dimension and may reduce the dimensionality. This is expected behavior.
Solution: Use at least two choices for optimization, or remove single-choice dimensions from bounds.
6.10 Summary
Factor variables in SpotOptim enable:
✅ Categorical optimization: Optimize over discrete string choices