Auriez-vous survécu au naufrage du Titanic?

Voici un petit exercice qui modélise avec un petit algorithme d'intelligence artificielle les chances de survie à la catastrophe du Titanic, en fonction de divers paramètres.
Je vous passe les détails techniques, le modèle est appelé Bayésien naïf, et on trouve d'excellentes explications sur Internet.

Pour l'exécuter, il vous faut un ESP32. Uploadez d'abord le fichier de données (voir tout en bas) dans le SPIFFS grâce à un plugin de l'IDE (au fait, est-ce qu'il est compatible de la v2 beta ?). Voir instructions ici :

Ensuite, installez la bibliothèque Naive Bayes, ici :

Il reste à téléverser le code suivant et à l'exécuter :

/*
   Naive Bayes algorithm implementation for the
   Titanic test case
   (c) Lesept, September 2021
*/
#include <Arduino.h>
#include "FS.h"
#include "SPIFFS.h"
#include "NaiveBayes.h"

#define FORMAT_SPIFFS_IF_FAILED true
const char * path = "/Clean_Dataset.csv";

#define nData 707
#define nFeatures 4
#define nClasses 2
NB Titanic(nData, nFeatures, nClasses);
std::vector<Data>dataset;

int inputInt() {
  String value;
  while (Serial.available() == 0) {}
  value = Serial.readString();

  if (value.length() > 0) {
    int n = value.toInt();
    Serial.println(n);
    return n;
  }
  return 0;
}

char inputChar() {
  String value;
  while (Serial.available() == 0) {}
  value = Serial.readString();

  if (value.length() > 0) {
    value.toUpperCase();
    char n = value.charAt(0);
    Serial.println(n);
    return n;
  }
  return 0;
}

void setup() {
  char buffer[50];
  Serial.begin(115200);

  // Mount SPIFFS
  if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }

  // Open dataset file
  File file = SPIFFS.open(path);
  if (!file || file.isDirectory()) {
    Serial.println("- failed to open file for reading");
    return;
  }

  // Read file
  Serial.printf("Reading data from file: %s\n", path);
  int n = 0;
  // Read a line
  while (file.available()) {
    int i = 0;
    char c = file.read();
    while (c != '\n') {
      buffer[i++] = c;
      c = file.read();
    }
    buffer[i] = NULL;

    // Extract numbers from the line
    if (n != 0) {
      char * pch = strtok(buffer, ";");
      int k = 0;
      uint8_t y = 0;
      std::vector<uint8_t> x;
      while (pch != NULL)
      {
        if (k == 0) {
          y = atoi(pch);
        }
        else {
          int u;
          if (k < 4) u  = atoi(pch);
          else {
            u  = atof(pch) / 2;
            if (u > 255) u = 255;
          }
          x.push_back(u);
        }
        k++;
        pch = strtok(NULL, ";");
      }
      // Add data to dataset
      //      Serial.printf ("%d -- %d %d %d %d --> survived %d\n", n, x[0], x[1], x[2], 2 * x[3], y);
      x.push_back(y);
      Titanic.addDataCat(x, dataset);
    } else Serial.println(buffer);
    n++;
  }
  file.close();
  Serial.printf("Read %d data from file\n", n - 1);

  // Fit the dataset
  Titanic.fit(dataset);

  int data[] = {2, 0, 5, 27};
  data[3] /= 2;
  if (data[3] > 255) data[3] = 255;
  std::vector<uint8_t> x (data, data + 4);
  uint8_t predict = Titanic.predictCatFit(x, dataset);
  Serial.printf("Prediction %d\n", predict);
}

void loop() {
  bool ok;
  Serial.println ("\n         _");
  Serial.println ("        / \\");
  Serial.println ("    __/ _  \\_                        ,   ,   ,");
  Serial.println ("   /_  -  \\  \\                      ,: ,: ,:  ");
  Serial.println ("  / / /     \\ \\                  __||_||_||_||___");
  Serial.println (" |    |  _  / |             ____[\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"]___");
  Serial.println (" /   /     \\   \\            \\ @ ''''''''''''''''''''/");
  Serial.println (" ~~^~^~~~^~^~^~~^~^~^~~~^~^~^^~^~^~^~^~^~^~^~~^~^~^~^~~^~^");
  Serial.println ("Did you survive the TITANIC ? ");
  ok = false;
  int age;
  while (!ok) {
    Serial.println("Enter your age (2 to 70)");
    age = inputInt();
    if (age > 1 && age < 71) ok = true;
  }

  ok = false;
  int sex;
  while (!ok) {
    Serial.println("Are you Male or Female (M or F) ? ");
    char c = inputChar();
    if (c == 'M' || c == 'F') ok = true;
    sex = (c == 'M') ? 1 : 0;
  }

  ok = false;
  int classe;
  while (!ok) {
    Serial.println("In which class did you travel (1, 2 or 3) ? ");
    classe = inputInt();
    if (classe > 0 && classe < 4) ok = true;
  }

  ok = false;
  int fare;
  while (!ok) {
    Serial.println("What is the fare of your trip (2 to 510 £) ? ");
    fare = inputInt();
    if (fare > 1 && fare < 511) ok = true;
  }

  int data[] = {classe, sex, age, fare / 2};
  std::vector<uint8_t> x (data, data + 4);
  uint8_t predict = Titanic.predictCatFit(x, dataset);
  for (int i = 0; i < 5 + random(15); i++) {
    Serial.print(".");
    delay(random(600));
  }
  Serial.printf((predict) ? "\nCongratulations, you survived !!!\n" : "\nSorry, you died...\n");
}

Bonne chance, et n'oubliez pas votre bouée de sauvetage...

Fichier de données : extrayez le fichier csv et mettez-le dans un répertoire data
Clean_Dataset.zip (2.6 KB)
Vous avez un répertoire Titanic, contenant :

  • Titanic.ino
  • data (répertoire dans lequel se trouve le fichier csv extrait de l'archive zip)

C'est interdit aux vieux sages ? :frowning:

C'est pour respecter la vérité historique. La base de données indique un âge maximum de 70 ans.

ah !

Mais tu peux retirer la condition pour voir s'il donne quand même des résultats au delà...

Ci dessous la toute dernière vraie photo du Titanic :

Et un instructables :

Auriez-vous survécu au naufrage du Titanic?

Uniquement si vous étiez étiez un passager de première classe.

L'histoire romancée des femmes et des enfants d'abord, à été mise à mal : seuls les passagers de première classe ont eu une possibilité de monter dans un canot, les autres passagers , hommes, femmes et enfants, ayant été enfermés à double tour dans leur cabine où ils étaient sûr de mourir.
Il ne fallait pas qu'ils prennent la place des riches dans les canots.

Excusez moi mais depuis que j'ai appris ces faits odieux j'ai un peu de mal à traiter le Titanic légèrement.