Titanic SwiftUI+ML (English version)
By: Tiago Poleze Ferreira
Tags: Turi Create, Swift, Swiftui, Python

In this article, I will try to explain a simple application using the turicreate framework to train a model and then use it to predict the percentage of chance of having survived the disaster of the Titanic. I obtained the data on the Kaggle platform , and all the code is on Github.

Part in Python

The turicreate framework uses Python, and I will use the Jupyter Notebook application through Anaconda. To download Anaconda, use this link. There find the download and do the same for your version of the operating system. I will use for macOS since later I will demonstrate the use on iOS. I hope you have access to the Apple system.

After installation, you open the app, and you will see this screen:

Anaconda Navigator

Click on the context Environments, in this context, click on Create, to create a new environment. Put the turicreate name and the python version in 3.7. Don’t add another version of Python.

After creating this new environment, click on the turicreate and play in this environment by choosing the option open Terminal.

Anaconda Environment

This action will open the Terminal, and you must enter the following commands.

pip install -U turicreate

conda install -c conda-forge jupyterlab

After installing turicreate and Jupiter Notebook in this * environment *, let’s go back to the Anaconda Navigator Home and launch Jupyter Notebook.

At this point, it is better to get the data that we will use, or in the GitHub repository above, only train.csv inside the data folder will be needed, or go to the Kaggle website and get the data there.

After being in the correct folder, the path using the turicreate is very straightforward.

We will import the turicreate to the project Let’s read the CSV data into a structure called SFrame. We will clean the data, excluding the empty values. (For an ML course, the ideal would be to arrange the data, but we will delete the lines with missing data for simplification) After that, we will divide the data into 80% and 20% into training data and test data. This test data will be useful later to evaluate the model. We are going to create two constants called target and an array called features . The target will be Survived , that is, whether the person survived or not. The features will be age, sex and class. If you want to test other features , feel free. In the next line, we will use turicreate magic and create the classifier. After this method, I put some others in the repository, to evaluate the model, in the case of one of the tests, the accuracy test, we had 76.92%, it is not perfect, but we can accept this without having had a lot of effort. Finally, we will use a method to export the model to CoreML, which is the one used in iOS to make predictions with the data placed.

# 1

import turicreate as tc

# 2

data = tc.SFrame.read_csv('./data/train.csv')

# 3

data = data.dropna()

# 4

train, test = data.random_split(0.8)

# 5

target = 'Survived'

features = ['Pclass', 'Sex', 'Age']

# 6

model = tc.classifier.create(train, target=target, features=features)

# 7

predictions = model.classify(test)

metrics = model.evaluate(test)

# 8

model.export_coreml('Titanic.mlmodel')

Here we finish the python part, and we will concentrate on the iOS application going forward.

Part in Swift

I will make the application as simple as possible, and for that, I will use the SwiftUI framework. In this part, I will go through the code more slowly, to explain a little what is happening here. Let’s start with the properties that we will use with @State .

import SwiftUI

struct ContentView: View {

@State private var pclass = "3"

@State private var age = "36"

@State private var sex = "male"

@State private var result = 0.00

// more to come

Here we create, as stated above, four attributes with this @State as property wrapper. This property that we gave to the variables is vital for the application, as they will keep the status of the program. This @State comes to circumvent a limitation of the swift, which is the case of the struct , after created, is fixed, that is, they cannot be modified, but attributes with this property wrapper can change the struct because SwiftUI is controlling this attribute. It may seem crazy because it would be much easier to take a class, but here we have a choice of architecture from the team that made SwiftUI and to be quite honest, all the applications that I saw until today that run SwiftUI do not lose in performance for the UIKit. I believe that the two will live in harmony for a long time.

Returning to the code, we created these four attributes to serve to save the data of the features that we chose in the turicreate and to present the result of the prediction, after calculating it.

Below these attributes, we will create two others, but without the need for @State , since they will be data that we will not modify.

private let sexs = ["male", "female"]

private let pclasses = ["1", "2", "3"]

We create these arrays to facilitate the choice process, as I will use a Picker , and these arrays will help to present the data we need.

After the lines above, we have a property with a particular name *computed property, which is the body property, in the form below:

var body: some View {

This variable computed property comes to suit the View protocol of the struct we are using. It is in this property that we will put all the code with the layout of the application, with all the buttons, navigation, texts and everything else that the user will see on the screen. Here we see that this property has the return type some View , that is, this property will return something that conforms to the View protocol, a Text , a Form or anything else that fits the View protocol, but not necessarily a specific return.

Now let’s speed up, that is, I will put a lot of code below, but if we analyze it, it is a lot of repeated things, that is, I will explain each structure only once and not line by line.

NavigationView {

Form {

Section(header: Text ("Passager class")) {

Picker(selection: $pclass, label: Text("\(pclass)")) {

ForEach(pclasses, id: \ .self ) {

Text ("\ ($ 0) º")

}

}

.pickerStyle(SegmentedPickerStyle())

}

Section(header: Text("Choose your sex")) {

Picker(selection: $sex, label: Text("\( sex)")) {

ForEach(sexs, id: \.self) {

Text("\($0)")

}

}

.pickerStyle(SegmentedPickerStyle())

}

Section(header: Text("Put your age")) {

TextField("\(age)", text: $age)

.keyboardType(.numberPad)

}

Section(header: Text("Classify button")) {

Button(action: {

self.calculatePercentual()

}) {

Text("Press to classify")

}

}

Section(header: Text("Percentage")) {

Text("\(result, specifier:"%.2f")%")

}

}

.navigationBarTitle("Titanic SwiftUI ML")

}

Here are some structures I want to explain:

NavigationView: This structure is not necessary for this project, but for visual effects, I put it here to use as a header with the modifying .navigationBarTitle . In other words, I used it only for aesthetic purposes, but it is a robust structure, where we can create a link with NavigationLink , buttons in the header created and other features, which I will not use here.

. In other words, I used it only for aesthetic purposes, but it is a robust structure, where we can create a link with , buttons in the header created and other features, which I will not use here. Form: This structure works as a List specialized in receiving data, so it has a form face.

specialized in receiving data, so it has a form face. Section: Another structure to improve the aesthetics of the application, to place a header explaining a little the data that we will receive or action that we will perform.

Picker: First structure in this list that I put into collecting data. Here we have the use of the power of @State , the ones with the property with the $ starts, allows us to modify the struct attribute. This structure does what its name says, creates a Picker to choose from a data set, which saves in the selected variable.

, the ones with the property with the $ starts, allows us to modify the attribute. This structure does what its name says, creates a Picker to choose from a data set, which saves in the selected variable. ForEach: This structure is beneficial for going through the data and repeating some other View elements, and this is where we make use of the sexs and pclasses attributes that we created to go through this array and use each item of the collection inside the closure ForEach .

elements, and this is where we make use of the and attributes that we created to go through this array and use each item of the collection inside the . Text: Perhaps the most used structure in SwiftUI, because it is with it that we can put texts on the screen for the user.

TextField: Second structure to capture data presented and serves to type with the keyboard what we want to receive. Note that in this structure, I put a modifier so that the keyboard only accepts numbers, because as we want to receive the age, we do not wish to allow the user to type the age in a cursive way.

Button: Structure to act, which here will be to calculate the percentage of chance of survival.

All structures have extensive documentation, and it would be not easy to explain all the ways to use them. Still, I hope that the code explains itself and the unspoken concepts used in the system, are to decorate the Design but without much impact on the result.

Finally, I will put here the use of the created model, but first, we need to import the model into Xcode, so that we can use the model.

All the logic is in the function, so I will put it below and explain after it.

func calculatePercentual() {

let model = Titanic()

if let pclass = Double(pclass) {

if let age = Double(age) {

do {

let prediction = try model.prediction(Pclass: pclass, Sex: sex , Age: age)

let probs = prediction.SurvivedProbability

if let prob = probs[1] {

result = prob * 100

}

} catch {

fatalError("\ (error)")

}

}

}

}

Now let’s go line by line:

Create the method. It takes no parameters and has no return. Create the model from Titanic , which is a class automatically generated by Xcode when we imported the model into IDE. As the pclass attribute is a String , we had to transform it into Double , because that is what the model will accept. Here the same thing from above, but for age . We start a do-catch, as there is a possibility that the prediction is nil , so it is good practice to place it inside a do-catch. We use the model and the attributes captured in the @State to make the model prediction with the past data. We take the survival probabilities, which is an array, with keys 0 or 1, that is, zero died, and one is alive. Finally, we take the probability of surviving, that is, as above, 1. We put the result in the result property, which as it is a property with @State , will update our view automatically. Nothing Capturing the error We kill the application by printing the error. Other lines NOTHING