Automatically telling whether a user review is positive or negative, without hand-coding a single rule, is what a machine learning text classifier does. Apple's Create ML framework lets you build one in a few lines of Swift. This tutorial trains a sentiment classifier on real review data, evaluates its accuracy, and tests it live in Playgrounds.
What Is a Sentiment Classifier?
A sentiment classifier reads a piece of natural language text (a review, a comment, a tweet) and predicts a label for it, typically positive or negative. Instead of writing brittle keyword-matching rules ("if the text contains 'bad', mark it negative"), you train the model on thousands of real, labeled examples, and it learns the underlying patterns itself.
Create ML, Apple's on-device model training framework, supports this out of the box through a class called MLTextClassifier. You do not need a data science background or an external ML pipeline. The entire workflow runs in Xcode Playgrounds.
What You'll Need Before You Start
- Xcode with Create ML and the Foundation/CreateML frameworks available
- A labeled dataset of text examples (reviews labeled positive or negative)
- Basic familiarity with Swift and Xcode Playgrounds
Step 1: Prepare Your Training Data
Every text classifier starts the same way an image classifier does: with labeled examples. For sentiment analysis, that means a large set of reviews, each tagged as positive or negative.
Where to get labeled review data:
- Write your own sample reviews and label them by hand (fine for small prototypes, not enough volume for real accuracy)
- Use real feedback your product already collects
- Pull from public sources like Amazon, Yelp, or IMDb (some offer APIs, others require web scraping)
- Use an existing labeled dataset, such as the Sentiment Labelled Sentences Data Set from the UCI Machine Learning Repository, which bundles 3,000 pre-labeled reviews from Amazon, Yelp, and IMDb
The UCI dataset is the fastest path to a working model, since the labeling work is already done for you.
Step 2: Convert Your Data to CSV Format
Create ML's MLDataTable class imports tabular training data from either JSON or CSV. The UCI dataset ships as raw text files, so it needs a quick conversion into a two-column CSV: one column for the review text, one for the label.
text,label
"But I recommend waiting for their future efforts, let this one go.",negative
"Service was very prompt.",positive
"I could care less... The interior is just beautiful.",positive
The first row must contain your column names (here, text and label), since MLDataTable uses those names as keys when you reference the data later.
You can do this conversion by hand, with a text editor's find-and-replace, or with a command-line tool like sed. On macOS, a sed one-liner can replace tab characters with the right label text and wrap each sentence in quotes in a single pass. Whatever method you choose, the end result just needs to be a clean two-column CSV with a header row.
Step 3: Load the Data and Split Training/Test Sets
Open a new Blank Playground under the macOS platform (this matters: Create ML training runs on macOS, not iOS), and import the framework:
import CreateML
import Foundation
let dataPath = URL(fileURLWithPath: "/path/to/sample_reviews.csv")
let dataSet = try MLDataTable(contentsOf: dataPath)
Rather than sourcing a separate test dataset, you can carve one out of your existing data using randomSplit:
let (trainingData, testingData) = dataSet.randomSplit(by: 0.8, seed: 5)
This holds back 20% of the data as a test set the model never sees during training, which is essential for judging how well it generalizes to real-world input rather than just memorizing examples.
Step 4: Train the Text Classifier with MLTextClassifier
With training data ready, the actual model training is a single line:
let textClassifier = try MLTextClassifier(
trainingData: trainingData,
textColumn: "text",
labelColumn: "label"
)
MLTextClassifier needs to know which column holds the input text and which holds the label. That's why textColumn and labelColumn are passed explicitly, matching the header names from your CSV. Running this line kicks off training immediately, using an underlying algorithm (MaxEnt) that iterates over the data, improving its accuracy with each pass.
Step 5: Check Training and Validation Accuracy
Once training finishes, you can inspect how well the model learned:
let trainingAccuracy = (1.0 - textClassifier.trainingMetrics.classificationError) * 100
let validationAccuracy = (1.0 - textClassifier.validationMetrics.classificationError) * 100
These two numbers reflect different things:
- Training accuracy reflects how well the model fits the data it was directly trained on. It is common to see this land near 99-100%.
- Validation accuracy reflects performance on a small slice (roughly 10%) of the training data that Create ML automatically sets aside during training to fine-tune the model. This number, often in the 80% range, is a more honest signal of real-world performance, since the model was not trained directly on those examples.
A large gap between training and validation accuracy is a classic sign of overfitting: the model has memorized the training data rather than learned generalizable patterns.
Step 6: Evaluate on Unseen Test Data
Validation accuracy is useful during training, but the real measure is how the model performs on data it has never encountered in any form: your held-out test set from Step 3:
let evaluationMetrics = textClassifier.evaluation(on: testingData, textColumn: "text", labelColumn: "label")
let evaluationAccuracy = (1.0 - evaluationMetrics.classificationError) * 100
This is the number to trust when deciding whether your model is ready to ship.
Step 7: Export the Trained Model
Once you're satisfied with the evaluation accuracy, save the model to disk as a .mlmodel file, along with metadata describing it:
if evaluationAccuracy >= 80.0 {
let modelInfo = MLModelMetadata(
author: "Your Name",
shortDescription: "A trained model to classify review sentiment",
version: "1.0"
)
try textClassifier.write(
to: URL(fileURLWithPath: "/path/to/SentimentClassifier.mlmodel"),
metadata: modelInfo
)
}
Gating the export behind an accuracy threshold (here, 80%) stops you from accidentally shipping a model that is not reliable.
Step 8: Test the Model in Playgrounds
Before wiring the model into a full iOS app, you can validate it directly in a Playground. First, compile the .mlmodel file into a .mlmodelc bundle from the Terminal:
xcrun coremlc compile SentimentClassifier.mlmodel .
Add the resulting SentimentClassifier.mlmodelc bundle to a new Playground's Resources folder, then load and run it using the NaturalLanguage framework's NLModel class:
import NaturalLanguage
let sampleReviews = [
"This beautiful piece of art is incredibly well written and directed, and the actors are doing a tremendous job!",
"We have found this machine to be extremely inconsistent.",
"I was very disappointed and will be returning it."
]
if let modelURL = Bundle.main.url(forResource: "SentimentClassifier", withExtension: "mlmodelc") {
let model = try! NLModel(contentsOf: modelURL)
for review in sampleReviews {
print(model.predictedLabel(for: review) ?? "")
}
}
Each review gets passed to predictedLabel(for:), which returns the model's prediction (positive or negative) directly in the console.
Alternative: Training with the Create ML App
Everything above can also be done without writing any Swift code. Launch the Create ML app, start a new project using the Text Classifier template, and assign your training and test CSV files through the UI. It runs the same underlying training process and produces the same .mlmodel output.
Try It Yourself: Build a Sentiment Analysis App
Once you have a trained .mlmodel file, the natural next step is wiring it into an actual iOS app. A simple version: a text view where users type a message, and on submit, the app classifies it and displays a thumbs up for positive sentiment or a thumbs down for negative. The integration code is identical to what you used to test the model in Playgrounds: just add the .mlmodel file to your iOS project target and call the same NLModel prediction logic from your view controller.
Summary
Training a sentiment classifier with Create ML follows the same rhythm as training an image classifier: collect labeled data, load it into MLDataTable, split it into training and test sets, train with a purpose-built class (MLTextClassifier here), and evaluate before shipping. What used to require a dedicated ML pipeline now fits in a dozen lines of Swift, turning a task that was previously impossible with simple pattern matching into something any iOS developer can build.
Frequently Asked Questions
What is the difference between training accuracy, validation accuracy, and evaluation accuracy? Training accuracy measures fit on the data used for training. Validation accuracy measures performance on a small held-out slice Create ML sets aside automatically during training. Evaluation accuracy measures performance on a completely separate test set you provide and is the most reliable indicator of real-world performance.
Can I use my own review data instead of the UCI dataset? Yes. Any dataset with a text column and a positive/negative label column, formatted as CSV or JSON, works with MLDataTable and MLTextClassifier.
Do I need an internet connection to run predictions with the trained model? No. Once compiled into a .mlmodelc bundle and added to your app, predictions run entirely on-device using the NaturalLanguage framework.
Why does the model need to be compiled with coremlc before testing in Playgrounds? Playgrounds and apps load the compiled .mlmodelc bundle, not the raw .mlmodel file. The coremlc compile command performs that conversion, which Xcode normally handles automatically when you add a model directly to an app target.