Scala
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Scala
-
Section 4: Functional Scala
-
Section 5: Collections in Depth
-
Section 6: Type System
-
Section 7: Concurrency and Ecosystem
-
Section 8: Practical Projects
-
Section 9: Interview Practice
-
Section 10: Data Structures and Algorithms in Scala
-
Section 11: More Practice Exercises
-
Section 12: Advanced Functional Patterns
-
Section 13: More Ecosystem
-
Section 14: Scala Collections Library Deep Dive
-
Section 15: Scala Standard Library Deep Dive
-
Section 16: Akka Ecosystem Deep Dive
-
Section 17: Cats and Cats Effect Deep Dive
-
Section 18: Play Framework Deep Dive
-
Section 19: Apache Spark with Scala Deep Dive
-
Section 20: Scala Build Tools Deep Dive
-
Section 21: Scala 3 Specific Features
-
90: Union and Intersection Types
-
Section 22: Scala Testing Deep Dive
-
Section 23: Functional Domain Modeling
-
Section 24: More Data Structures and Algorithms in Scala
-
Section 25: Scala for Data Engineering
-
Section 26: More Practical Projects
-
Section 27: More Interview and Review
-
Section 28: ZIO Ecosystem Deep Dive
-
Section 29: Scala for Machine Learning
-
Section 30: Scala Microservices Architecture
-
Section 31: Scala Type System Deep Dive
-
Section 32: More Practice and Drills
-
Section 33: Scala Performance Deep Dive
-
Section 34: Scala Ecosystem Tooling
-
Section 35: Scala for Reactive Systems
-
Section 36: More Real-World Case Studies
-
Section 37: Scala for Financial Systems
-
Section 38: Scala GraphQL and gRPC
-
Section 39: More Final Projects
-
Section 40: More Interview and Final Review
-
Section 41: Scala for Streaming Data
-
Section 42: Scala Security Practices
-
Section 43: More Language Deep Dive
-
Section 44: Scala Command-Line Tools
-
Section 45: Scala Documentation and Style
-
Section 46: Scala Dependency Management
-
Section 47: More Practical Backend Patterns
-
Section 48: Scala for Event-Driven Architecture
-
Section 49: More Practice Drills Round 2
-
Section 50: Scala Compiler Deep Dive
-
Section 51: Scala for Web Frontends
-
Section 52: More Data Engineering Practice
-
Section 53: Scala Observability
-
Section 54: More Advanced Practice Projects
-
Section 55: Scala for Legacy Java Integration
-
Section 56: More Testing Practice
-
Section 57: Final Mastery Review
-
Section 58: Scala History and Ecosystem Context
-
Section 59: More Concurrency Patterns
-
Section 60: Scala for Configuration Management
-
Section 61: More Domain Modeling Practice
125: Feature Engineering in Spark
I remember a developer I mentored a few years back—let's call him Alex—who was convinced his machine learning model was fundamentally broken. He had spent three days obsessively tuning hyperparameters for a Random Forest classifier, tweaking the tree depth and the number of estimators, but the accuracy wouldn't budge past 62%. He came to me frustrated, claiming the data "just wasn't predictive." When I looked at his Spark DataFrame, I saw the problem immediately: he was feeding raw timestamps and city names directly into the model, and his "Annual Income" column (ranging from 30k to 500k) was completely drowning out his "Years of Experience" column (ranging from 0 to 40).
The hard truth in ML is that your model is only as good as the features you feed it. In Spark MLlib, you can't just throw a DataFrame at an algorithm and hope for the best. Most Spark ML algorithms expect a single column—usually called features—that contains a Vector of doubles. Feature engineering is the process of turning your messy, real-world columns into that single, optimized vector.
Turning Categories into Math with Indexing and Encoding
Computers aren't great with strings like "New York" or "London." To make this data usable, we first use a StringIndexer. This maps each unique string to a number (e.g., "New York" becomes 0.0, "London" becomes 1.0). But there's a catch: if you leave it at that, the model might assume that "London" is "greater than" "New York" simply because 1.0 is bigger than 0.0. This is called ordinal bias, and it can wreck your results.
To fix this, we use OneHotEncoder. It transforms those indices into a binary vector. Instead of a single column with the value 1.0, you get a vector like (0, [1]), meaning the second category is active. I've found that skipping this step is the most common reason why beginners see weird patterns in their model weights.
val indexer = new StringIndexer() .setInputCol("city") .setOutputCol("cityIndex") val encoder = new OneHotEncoder() .setInputCol("cityIndex") .setOutputCol("cityVec") val indexedDF = indexer.fit(df).transform(df) val encodedDF = encoder.fit(indexedDF).transform(indexedDF)Normalizing Scales and Assembling the Feature Vector
Once your categories are handled, you have to deal with the "magnitude problem." If one feature is "Age" (0-100) and another is "Annual Salary" (0-1,000,000), the salary will dominate the distance calculations in many algorithms. I always recommend using a
MinMaxScalerto squash all numeric values into a range between 0 and 1. This puts everyone on a level playing field.The final piece of the puzzle is the
VectorAssembler. This is the "glue" of Spark ML. It takes a list of multiple columns—your one-hot encoded vectors and your scaled numbers—and merges them into a single vector column. This is the exact format thatDecisionTreeClassifierorLogisticRegressionrequires. If you try to pass a DataFrame without a combined vector column, Spark will throw an AnalysisException that's surprisingly vague, so keep this step in mind.val scaler = new MinMaxScaler() .setInputCol("salary") .setOutputCol("salaryScaled") val assembler = new VectorAssembler() .setInputCols(Array("salaryScaled", "cityVec", "experience")) .setOutputCol("features") val scaledDF = scaler.fit(encodedDF).transform(encodedDF) val finalDF = assembler.transform(scaledDF)
📋 Practical Task
Exercise: Building a Customer Churn Feature Pipeline
You have a DataFrame containing customer data with three columns: plan_type (String: "Basic", "Premium", "Enterprise"), monthly_spend (Double), and support_tickets (Integer). Your goal is to prepare this data for a churn prediction model.
Write a Scala Spark program that performs the following:
- Use
StringIndexerto convertplan_typeinto numeric indices. - Use
OneHotEncoderto transform those indices into a binary vector. - Use
MinMaxScalerto scalemonthly_spendandsupport_ticketsto a range between 0 and 1. (Hint: You may need to use aVectorAssemblerfirst to combine the numeric columns before scaling, or scale them individually if using a custom approach). - Use a final
VectorAssemblerto combine the one-hot encoded plan and the scaled numeric values into a single column namedfeatures.
Print the final DataFrame to verify that you have a features column containing a SparseVector or DenseVector.
There are no comments for now.