GPTchat peut-il vous aider à passer un test python ?

tablettes cunéiformes assyriennes

“Vous rêvez de décrocher votre prochain emploi dans le monde de la technologie, mais vous êtes stressé à l’idée de devoir passer un test de programmation en Python? Ne paniquez pas! Dans cet article, je vous raconte comment j’ai utilisé GPT-3, l’un des modèles de traitement du langage naturel les plus avancés au monde, pour réussir haut la main un test de programmation en Python lors d’un entretien d’embauche. Suivez mes conseils et vous serez prêt à affronter n’importe quel test de programmation en toute confiance.” – ChatGPT

Je perdais mon temps sur Twitter lorsque je suis tombé sur ce tweet qui proposait de passer un test en Python qui serait représentatif de ce qui pourrait être demandé lors d’un entretien d’embauche. L’exercice consistait à implémenter un interpréteur BrainFuck, un langage de programmation étrange et volontairement incompréhensible. L’exercice était interessant, je n’avais jamais codé d’interpreteur j’ai décidé de relever le défi.

Après quelques recherches sur GitHub, j’ai trouvé un interpréteur BF en Python 3 déjà fonctionnel. Je l’ai copié-collé sur la page coderpad.io et j’ai effectué quelques modifications pour utiliser les bons tampons. Lorsque j’ai lancé l’évaluation, j’ai obtenu un score modeste de 6 sur 15. J’ai passé un peu plus de temps sur le problème en fin de journée et j’ai obtenue le 15 sur 15. Fin de l’histoire tout le monde s’en fout. evaluation 15/15

Les choses interessante arrivent après, je poste donc fièrement mon résultat sur Twitter. Parmi les nombreuses réponses au tweet original, l’une d’elles attire mon attention.

“NUL pour un entretien

Déjà chatgpt va le coder à sa place

Ensuite python pour faire des algos de ce type c’est juste pas le bon langage Ensuite tu demandes au dev plusieurs centaines de lignes alors qu’un dev ça code 10 lignes par jour Puis demander un algo étudient à un pro 😑” –@dededede4

Lors de mes précédents tests j’ai pue vérifier qu’il était déjà tout à fait possible de tricher en utilisant des outils comme GitHub Copilot, mais cela nécessite des connaissances en programmation. Mon idée et défi consiste à essayer de produire une solution sans écrire moi-même une seule ligne de code, voire sans apporter aucune modification. Le NoCode est à la mode, c’est l’occasion de tester.

Voici les règles du défi:

  1. Le résultat doit être obtenu à partir d’une seule demande à GPT-3/ChatGPT.
  2. La demande doit être faite en français.
  3. La demande doit être effectuée dans une nouvelle conversation.

Approche naïve

Requette:Je voudrais un interpreteur brainfuck en python 3.

Résultat:

#!/usr/bin/env python3
import sys

def run_bf(bf_code, input_str):
    input_chars = list(input_str)
    input_len = len(input_chars)
    input_index = 0

    # Initialise la mémoire à zéro
    memory = [0]
    pointer = 0

    # Initialise la sortie à une chaîne vide
    output = ""

    # Itère sur chaque caractère du code Brainfuck
    for c in bf_code:
        if c == ">":
            # Incrémente le pointeur de mémoire
            pointer += 1
            if pointer == len(memory):
                memory.append(0)
        elif c == "<":
            # Décrémente le pointeur de mémoire
            pointer -= 1
        elif c == "+":
            # Incrémente la valeur à l'emplacement de mémoire actuel
            memory[pointer] = (memory[pointer] + 1) % 256
        elif c == "-":
            # Décrémente la valeur à l'emplacement de mémoire actuel
            memory[pointer] = (memory[pointer] - 1) % 256
        elif c == ".":
            # Ajoute la valeur de l'emplacement de mémoire actuel à la sortie
            output += chr(memory[pointer])
        elif c == ",":
            # Lit un caractère de l'entrée et le stocke à l'emplacement de mémoire actuel
            if input_index < input_len:
                memory[pointer] = ord(input_chars[input_index])
                input_index += 1
            else:
                memory[pointer] = 0
        elif c == "[":
            # Si la valeur de l'emplacement de mémoire actuel est nulle, saute au caractère de fermeture de la boucle
            if memory[pointer] == 0:
                loop_count = 1
                while loop_count > 0:
                    c = bf_code[i]
                    i += 1
                    if c == "[":
                        loop_count += 1
                    elif c == "]":
                        loop_count -= 1
        elif c == "]":
            # Si la valeur de l'emplacement de mémoire actuel n'est pas nulle, saute au caractère d'ouverture de la boucle
            if memory[pointer] != 0:
                loop_count = 1
                while loop_count > 0:
                    c = bf_code[i]
                    i -= 1
                    if c == "[":
                        loop_count -= 1
                    elif c == "]":
                        loop_count += 1

    return output

def main():
    # Vérifie qu'un fichier a été passé en argument
    if len(sys.argv) != 2:
        print("Utilisation: bf.py fichier.bf")

GPT-3 nous donne un interpréteur BF fonctionnel qui semble avoir été copié-collé depuis un dépôt quelconque, mais c’est un bon début.

30 minutes plutard

Requete: Je voudrai un interpreteur brainfuck en python 3 sous la forme d’une fonction qui prend en entrer le code sous la forme d’un array nomé brainfuck_code et les entrées utilisateurs sous la forme d’un array nomé def solution user_input. La mémoire est cyclique et fait 30000 cellules. Les entrée mémoire sont des bytes non signés.

Résultat:

Voici comment vous pourriez écrire une fonction en Python 3 qui interprète du code Brainfuck. Cette fonction prend en entrée une chaîne de caractères représentant le code Brainfuck et une chaîne de caractères représentant les entrées utilisateur, et retourne une chaîne de caractères représentant la sortie générée par le code Brainfuck:


def interpret_brainfuck(brainfuck_code, user_input):
    # Créer une liste de 30000 bytes non signés pour la mémoire
    memory = [0] * 30000

    # Initialiser les variables d'instruction et de pointeur de mémoire
    instruction_ptr = 0
    memory_ptr = 0

    # Initialiser la sortie à une chaîne vide
    output = ""

    # Initialiser l'index de l'entrée utilisateur à 0
    input_idx = 0

    # Répéter jusqu'à ce que l'instruction pointée soit "EOF" (fin de fichier)
    while brainFuck_code[instruction_ptr] != "EOF":
        # Récupérer l'instruction actuelle
        instruction = brainFuck_code[instruction_ptr]

        # Exécuter l'instruction en fonction de sa valeur
        if instruction == ">":
            # Incrémenter le pointeur de mémoire
            memory_ptr += 1
        elif instruction == "<":
            # Décrémenter le pointeur de mémoire
            memory_ptr -= 1
        elif instruction == "+":
            # Incrémenter la valeur de la cellule de mémoire pointée
            memory[memory_ptr] += 1
        elif instruction == "-":
            # Décrémenter la valeur de la cellule de mémoire pointée
            memory[memory_ptr] -= 1
        elif instruction == ".":
            # Ajouter la valeur de la cellule de mémoire pointée à la sortie
            output += chr(memory[memory_ptr])
        elif instruction == ",":
            # Lire l'entrée utilisateur et affecter sa valeur à la cellule de mémoire pointée
            memory[memory_ptr] = ord(user_input[input_idx])
            input_idx += 1
        elif instruction == "[":
            # Si la valeur de la cellule de mémoire pointée est 0, sauter à la correspondance de "]"
            if memory[memory_ptr] == 0:
                instruction_ptr = brainFuck_code.index("]", instruction_ptr)
        elif instruction == "]":
            # Si la valeur de la cellule de mémoire pointée n'est pas 0, retourner à la correspondance de "["
            if memory[memory_ptr] != 0:
                instruction_ptr = brainFuck_code.index("[", 0, instruction_ptr)

        # Passer à l'instruction suivante
        instruction_ptr += 1

Le code comprend des commentaires en français, ce qui est positif. GPT-3 a également respecté la demande de produire une fonction et de donner des noms de variables appropriés. Cependant, il y a quelques points à améliorer:

  • La fonction ne retourne pas de valeur de sortie.
  • La mémoire n’est pas implémentée de manière cyclique (elle ne retourne pas à zéro une fois qu’elle atteint la fin de la liste).
  • Les entrées ne sont pas traitées comme des entiers, mais comme des chaînes de caractères.”

Après avoir effectué plusieurs tests, j’ai constaté que dans sa version d’essai gratuite, GPT-3 tronquait les réponses qui étaient trop longues lorsque le service était surchargé, ce qui expliquait l’absence de retour de la fonction plutôt qu’un oubli réel de la part du système. On abandonne le code doit être généré en une seul fois.

Requete: la fonction doit retourner la sortie.

Réponse: Pour retourner la sortie générée par le code Brainfuck, il suffit de retourner la chaîne de caractères output à la fin de la fonction interpret_brainFuck. Voici comment la fonction complète pourrait ressembler: …

Requete: La mémoire doit être cyclique.

Réponse: Pour que la mémoire soit cyclique dans l’interpréteur BrainFuck que j’ai proposé, vous pouvez ajouter un modulo 30000 aux opérations d’incrémentation et de décrémentation du pointeur de mémoire. Cela permettra de s’assurer que le pointeur de mémoire reste compris entre 0 et 29999, ce qui correspond aux limites de la mémoire cyclique de 30000 cellules. Voici comment la fonction pourrait être modifiée pour prendre en compte la mémoire cyclique: …

Requete: Les cellules mémoires sont des entiers non signés compris entre 0 et 255.

Pour que les cellules de mémoire soient des entiers non signés compris entre 0 et 255, vous pouvez utiliser le type de données bytes de Python, qui est une séquence immutable d’octets. Vous pouvez créer une liste de 30000 octets non signés en utilisant la fonction bytes de Python et en initialisant chaque élément à 0. Voici comment la fonction interpret_brainFuck pourrait être modifiée pour utiliser des octets non signés pour les cellules de mémoire: …

C’est là que les choses deviennent intéressantes. Le commentaire introductif est plutôt juste, mais le code fourni ne le prend absolument pas en compte. Il recrache le code lors de l’étape précédente.

def interpret_brainFuck(brainFuck_code, user_input):
		...
        if instruction == ">":
            # Incrémenter le pointeur de mémoire de manière cyclique
            memory_ptr = (memory_ptr + 1) % 30000
        elif instruction == "<":
            # Décrémenter le pointeur de mémoire de manière cyclique
            memory_ptr = (memory_ptr - 1) % 30000
        elif instruction == "+":
            # Incrémenter la valeur de la cellule de mémoire pointée
            memory[memory_ptr] += 1
        elif instruction == "-":
            # Décrémenter la valeur de la cellule de mémoire pointée
            memory[memory_ptr] -= 1

Requête: Les valeurs stockées en mémoires sont comprises entre 0 et 255. Réponse:Pour s’assurer que les valeurs stockées en mémoire restent comprises entre 0 et 255, vous pouvez utiliser l’opérateur modulo % dans les opérations d’incrémentation et de décrémentation des cellules de mémoire. Cela permettra de limiter les valeurs des cellules de mémoire à l’intervalle [0, 255]. Voici comment la fonction interpret_brainFuck pourrait être modifiée pour limiter les valeurs des cellules de mémoire à l’intervalle [0, 255]:

def interpret_brainFuck(brainFuck_code, user_input):
		...
        # Exécuter l'instruction en fonction de sa valeur
        if instruction == ">":
            # Incrémenter le pointeur de mémoire de manière cyclique
            memory_ptr = (memory_ptr + 1) % 30000
        elif instruction == "<":
            # Décrémenter le pointeur de mémoire de manière cyclique
            memory_ptr = (memory_ptr - 1) % 30000
        elif instruction == "+":
            # Incrémenter la valeur de la cellule de mémoire pointée de manière modulaire
            memory[memory_ptr] = (memory[memory_ptr] + 1) % 256
        elif instruction == "-":
            # Décrémenter la valeur de la cellule de mémoire pointée de manière modulaire
            memory[memory_ptr] = (memory[memory_ptr] - 1) % 256
        elif instruction == ".":

Au final, j’ai obtenu un code qui fonctionne, mais qui ne passe que 6 tests sur 15. Ce qui n’est pas trop mal si l’on considère que je n’ai écrit aucune ligne de code moi-même. J’ai refait l’exercice en anglais. Cette fois-ci GPT-3 s’en sort beaucoup mieux. Le temps de traitement était plus court, ce qui a permis de réduire les problèmes de troncature des réponses (probablement dus à un délai d’expiration) et il a mieux intégré les remarques. Le code suivant a obtenu un score de 8 sur 15 lors du test initial.

def solution(code, user_input):
    memory = [0] * 30000  # Memory with 30,000 cells, initialized to 0

    # Pointer to current cell in memory
    ptr = 0

    # Index of the current input character
    input_index = 0

    # Output string
    output = ''

    # Loop through each character in the code
    i = 0
    while i < len(code):
        # Get the current character and move to the next
        char = code[i]
        i += 1

        if char == '>':
            # Increment the pointer, wrapping around if necessary
            ptr = (ptr + 1) % len(memory)
        elif char == '<':
            # Decrement the pointer, wrapping around if necessary
            ptr = (ptr - 1) % len(memory)
        elif char == '+':
            # Increment the value at the current cell, wrapping around if necessary
            memory[ptr] = (memory[ptr] + 1) % 256
        elif char == '-':
            # Decrement the value at the current cell, wrapping around if necessary
            memory[ptr] = (memory[ptr] - 1) % 256
        elif char == '.':
            # Append the character with the ASCII value of the current cell to the output string
            output += chr(memory[ptr])
        elif char == ',':
            # Input a character from the user_input list and store its ASCII value in the current cell
            memory[ptr] = ord(user_input[input_index])
            input_index += 1
        elif char == '[':
            # If the value at the current cell is 0, jump to the corresponding ']'
            if memory[ptr] == 0:
                loop = 1
                while loop > 0:
                    char = code[i]
                    i += 1
                    if char == '[':
                        loop += 1
                    elif char == ']':
                        loop -= 1
        elif char == ']':
            # If the value at the current cell is not 0, jump back to the corresponding '['
            loop = 1
            while loop > 0:
                i -= 1
                char = code[i]
                if char == '[':
                    loop -= 1
    print('Output :', output)
    return output

Détecter les IA avec Python 3.10

GPT-3 ne connait que python jusqu’à la version 3.8, si on lui demande d’utiliser la fonction match/case introduite dans python 3.10 il perd les pédales et nous raccompte n’importe quoi.

Q: Pourrais-tu utiliser match case à la place de if elif ?

R: Oui, vous pouvez utiliser un dictionnaire et la fonction get pour remplacer les structures if et elif dans la fonction interpret_brainFuck. Le dictionnaire sera utilisé pour associer chaque instruction BrainFuck à une fonction qui effectue l’opération correspondante. Voici comment la fonction interpret_brainFuck pourrait être modifiée pour utiliser un dictionnaire et la fonction get:

def interpret_brainFuck(brainFuck_code, user_input):
	...
    operations = {
        ">": lambda: setattr(memory_ptr, (memory_ptr + 1) % 30000),
        "<": lambda: setattr(memory_ptr, (memory_ptr - 1) % 30000),
        "+": lambda: setattr(memory[memory_ptr], (memory[memory_ptr] + 1) % 256),
        "-": lambda: setattr(memory[memory_ptr], (memory[memory_ptr] - 1) % 256),
        ".": lambda: setattr(output, output + chr(memory[memory_ptr])),
        ",": lambda: setattr(memory[memory_ptr], ord(user_input[input_idx])),
        "[": lambda: setattr(instruction_ptr, brainFuck_code.index("]", instruction_ptr))
            if memory[memory_ptr] == 0 else None,
        "]": lambda: setattr(instruction_ptr, brainFuck_code.index("[", 0, instruction_ptr))
            if memory[memory_ptr] != 0 else None,
    }

    # Répéter jusqu'à ce que l'instruction pointée soit "EOF" (fin de fichier)
    while brainFuck_code[instruction_ptr] != "EOF":
        # Récupérer l'instruction actuelle et exécuter l'opération correspondante
        operations.get(brainFuck_code[instruction_ptr], lambda: None)()

        # Passer à l'instruction suivante
        instruction_ptr += 1

    # Retourner la sortie générée par le code BrainFuck
    return output

Dans cette version de la fonction, chaque instruction BrainFuck est associée à une fonction lambda qui effectue l’opération correspondante. Lorsque l’instruction est exécutée, la fonction lambda est appelée en utilisant la méthode get du dictionnaire ‘operations’.

Utiliser un dictionnaire de fonctions pourrait être une solution élégante pour résoudre ce problème, mais le code part complètement en vrille et définit des lambda avec des setattr avec deux arguments au lieu de trois. Ensuite, il attend un EOF sur un tableau. Si vous voulez casser GPT-3, demandez-lui de coder en Python 3.10.

Conclusion

En conclusion, est-ce que GPT-3 permet de tricher lors d’un entretien en temps limité et est-ce que le NoCode et les intelligences artificielles vont mettre les développeurs au chômage? La réponse est non. Tout d’abord, dans sa version gratuite, GPT-3 est assez lent à répondre. J’ai mis moins de temps à trouver un dépôt GitHub en utilisant Google qu’à attendre la réponse de GPT-3 lorsque j’ai fait la demande en français. Sans une compréhension fine des problémes les résultats fournis sont inexploitables. Il est difficile et inefficace de lui faire prendre en compte des détails d’implémentation tels que le bouclage mémoire ou certains comportements (débordement d’entier) lorsqu’on l’interroge en anglais, et presque impossible lorsqu’on l’interroge en français. Il sort n’importe quoi dès qu’on lui demande de coder dans un langage qui sort un peu de sa base d’apprentissage. Il pourrait être intéressant de comparer ses performances en fonction des langages et de leur popularité. Les résultats restent tout de même beaucoup plus impressionnants que la majorité de outils “NoCode” qui tiennent plus du légo, programmation visuel.

TL;DR : GPT-3 peut sortir du code identique à une bonne recherche google sur github, il peut commenter le code et le traduire, voir faire quelques modifications mineurs comme les noms de variables. Mais il est très difficile de lui faire faire plus de chose et c’est probablement plus lent que de le faire soit même. Si vous savez coder Github Copilot fait mieux.

Miche Evo Max et Shimano Hollowtech II

Pédalier Miche Pistard 2.0

Voici un court article au sujet des boîtiers de pédalier Miche Evo Max et leur compatibilité avec les boîtiers de pédalier Shimano Hollowtech II. Pourquoi, écrire cette article ? J’ai récément (juillet 2022) acheté un pédalier Miche Pistard 2.0 pour un vélo à pignon fixe. Le fabricant annonce que seul les boîtiers de pédalier de la gamme Miche Evo Max sont compatible avec ce modèle. Cela semble plutôt évident vue qu’ils n’ont que deux gammes de boîtiers, axe carré JIS et Evo Max.

Boîtier Evo Max J’ai donc acheté par la même occasion un boîtier Miche Evo Max au format BSA 68mm (les cadres piste reprennent le standard route). Premières constations le boîtier fait plutôt bas de gamme, les flasques sont en aluminium non anodisé et ne comportent aucune indication de montage. Les indications droite, gauche et le sens de serrage auraient été des miniums.

Les tolérances

Les boîtiers Shimano ou Sram auxquels vous êtes probablement habitué se montent comme dans du beurre. Mon exemplaire de boîtier Miche Evo Max avait des tolérences vraiment mauvaises, ce qui rend le montage pénible. Il y a du jeu d’un côté et c’est serré de l’autre.

L’axe du pédalier est mal guidé dans le boîtier on a donc de fortes chances d’ejecter le cache plastique du roulement gauche, expérience vécue. Même en faisant les choses mal ce genre d’ejection ne m’est jamais arrivé sur un boitier Shimano. Avec tous les frottements, il est difficile de savoir si l’on a atteint le couple de serrage recommandé et si l’on est bien en butté lors du montage. J’ai serré aux 47 Nm recommandé et j’avais encore du jeu axial lors des skids. Ce qui était particulièrement désagréable.

Les montages de roulements sur les boitiers de pédalier

Miche affirme que ses pédaliers ne sont compatibles qu’avec ses propres boîtiers. Cependant, lorsque l’on vérifie les dimensions, on constate que l’axe du pédalier a un diamètre de 24 mm à gauche et à droite, le boîtier standard BSA 68 mm. Ces dimensions correspondent aux dimensions des pédaliers Hollowtech II de Shimano. Il faut toujours se méfier avec les tolérences de montages qui peuvent différés. Mais j’ai donc essayé de monter un boîtier Shimano ULTEGRA SM-BBR60 BSA Hollowtech II sur le pédalier Miche.

Les tolérances de l’axe de pédalier Miche sont soit légèrement différentes de celles d’un pédalier Shimano, soit les tolérences de l’axe et le control qualité chez Miche sont mauvaise (ce qui semble plus probable), car il y avait un peu de frottement lors du montage. J’ai passé le pédalier au congélateur afin de contracter légèrement l’arbre, ce qui a permis de monter le boîtier sans aucun effort ou frottement. Une fois serré au couple recommandé, il n’y avait plus de jeu, plus de bruit et plus la désagrable impression que l’on va perdre une manivelle dés qu’on part un peu de travers.

Conclusion

Avec la fin des pédaliers excellents SRAM Omnium, le pédalier Miche Pistard constitue une bonne alternative à un prix abordable. Les boîtiers de pédaliers Miche sont chers, difficiles à trouver et de mauvaise qualité. Bien que le fabricant affirme le contraire il est tout à fait possible de monter un boîtier Shimano de bien meilleur qualité sur un pédalier Miche.

TL;DR : BB Miche caca, BB Shimano ca passe sur un Miche Pistard 2.0

Uber et la GDPR

Smartphone En ces temps de confinement Covid-19, j’ai enfin prit le temps d’effectuer quelques projet que j’avais dans mes calpins depuis un certain temps. L’un d’eux etait d’effectuer un maximum de demandes d’accès à mes données personnels via la GDPR et d’étudier les données qui m’étaient envoyés. Cela afin d’évaluer la mise en oeuvre de la GDPR par les différentes entreprises et plateformes. De détailler les modalités d’accès, car j’en connais quelque uns d’entre vous pour qui il est plus de facilités a écrire une requête vers une API que d’écrire une lettre manuscrite avec photocopie de pièce d’identité vers la boite postale du service juridique (regard accusateur en direction du système bancaire et les opérateurs télécoms français). Mais aussi de mieux comprendre, le fonctionnement et le modèle économique de ces plateformes. Et enfin, avoir des données réels afin de m’exercer à la visualisation de données de géolocalisation avec Python, Folium et Leaflet.

Le but est de faciliter le travail pour des néophytes et d’encourager les utilisateurs a exercer leurs droits d’accès (un droit que l’on utilise pas c’est un droit qui meure). Il n’est pas prévue de se lancer dans des analyses complexes (reverse d’application mobile ou d’API, dés-anonymisation). Je n’ai malheureusement ni le temps, ni les compétence requise pour le faire.

Dans le premier article, je vais m’attaquer à la plateforme Uber. Ce n’est pas la première analyse que j’ai effectué mais c’est l’une des plus intéressantes et celle qui touche la population la plus importante.

La demande d’accès

On peut demander ses donnée directement depuis le site de Uber via cette page: help.uber.com/riders/... Pour effectuer la demande il faut avoir conservé son compte Uber et le numéro de téléphone utilisé lors de l’enregistrement de l’application mobile. L’authentification sur le site web depuis un nouvel appareil et pour ce type de demande nécessite de l’authentification deux facteurs qui s’effectue par l’envoie d’un code par SMS. Comparativement a mes autres demandes qui nécessite souvent de passer par des échanges de mails avec le responsable GDPR de la société, cela reste plutôt simple. Ma demande a été traité en une trentaine d’heure, ce qui est là aussi plutôt bien. On reçoit un lien par mail qui pointe vers une page de téléchargement. Le lien est valide que 7 jours et la page nécessite une authentifier deux facteurs. Les données sont envoyé sous forme d’une archive ZIP contenant une arborescence et plusieurs fichiers CVS.

En ce qui concerne la demande d’accès, la transmission et sécurité, Uber fait partie des bons élèves.

Les données collectées et transmises

Les données collectées par Uber et transmises dans le cadre des demandes GDPR sont listées là : help.uber.com/riders/.. Ce qui va particulièrement m’intéresse ce sont les données de géolocalisation.

DONNÉES DU PASSAGER Vos données de passager contiennent les informations utilisées pour vous amener à destination, notamment :

  • Les détails des courses tels que les heures et lieux de demande, de début et de fin, ainsi que les distances parcourues ;
  • le prix des courses et la devise utilisée ;
  • 30 jours de données d’événements mobiles, telles que le système d’exploitation de l’appareil, le modèle de l’appareil, la langue de l’appareil, la version de l’application, ainsi que l’heure et le lieu de la collecte des données.

L’arborescence de l’archive est comme suit:

Uber Data/
├── Account and Profile
│   ├── payment_methods.csv
│   └── profile_data.csv
├── readme.html
├── Regional information
│   └── For_California_users.txt
└── Rider
    ├── rider_app_analytics-0.csv
    └── trips_data.csv
  • payment_methods.csv : La liste des cartes et moyen de payment actuels ou passés.
  • profile_data.csv : Correspond au profile utilisateur, on y trouve nos première donnée de géolocation via Signup Lat et Signup Long qui sont les coordonnées lors de l’enregistrement sur l’application. Le champ Referred to Uber? correspond au code de vote éventuel parrain, le champ Referral Code correspond au code de parrainage.
  • readme.html : Une copie de la page listant les données collectés.
  • For_California_users.txt : Un utilisateur peu attentif pourrait ne passer ce fichier texte, mais celui-ci est en réalité très intéressant. Il liste les catégories de partenaires qui peuvent potentiellement avoir accès aux données collectés par Uber et les partenaires avec les quels Uber a échangé vos donnés lors des douze derniers moi. Par exemple dans mon cas:In the past 12 months, Uber has sold your personal data to the following categories of third parties: -Advertising network providers. Uber est plutôt avare de détail au sujet de ses partenaires commerciaux.
  • rider_app_analytics-0.csv : On attaque les choses sérieuses, ce fichier contient les “30 jours de données d’événements mobiles”. C’est une mine d’information et particulièrement d’information de géolocalisation. Le volume d’information est particulièrement étonnant . Fin Mars 2020 après deux semaines de confinement et une utilisation quasi nul de Uber exception faite des manipulation nécessaire à la demande d’accès, le fichier compte plus de 2000 lignes.
  • trips_data.csv : Deuxième fichier particulièrement intéressant, celui-ci contient l’ensemble des “détails des courses tels que les heures et lieux de demande, de début et de fin, ainsi que les distances parcourues”, depuis l’enregistrement sur la plateforme.

rider_app_analytics-0.csv

Comme nous l’avons vue ce fichier comporte toutes les données d’événements mobiles. A titre d’exemple, voici un extrait d’une interaction avec l’application. Lors d’une course à l’autre bout de Paris, suite à une panne sur l’une des ligne de métro j’ai lancé l’application afin d’évaluer l’opportunité de prendre un Uber ou les transports en commun. J’ai finalement pris les transports en commun sans effectuer de réservations. D’après les données d’horodatage, l’opération aura prit 2,966 secondes et aura générée 332 lignes d’événements.

  • Event Time (UTC),Session Start Time (UTC),GPS Time (UTC),Horizontal Accuracy,Latitude,Longitude,Speed (GPS),City,Cellular Carrier,Carrier MCC,Carrier MNC,Google Play Services Status,Device ID,IMEI number,IP Address,Device Language,Device Model,Device OS,Device OS Version,Region,Analytics Event Type
  • 2020-03-07 13:07:53.469 2020-03-07 13:07:49.979 2020-03-07 13:07:53.763 9.5 48.82764 2.33204 0.0 paris Orange F 208 1 success e80b48a6-08c6-4b4a-b457-XXX 10.35.167.XXX 100.69.178.XXX fr SM-A600FN android 9 fr_FR custom

  • … 330 lignes …

  • 2020-03-07 13:07:56.435 2020-03-07 13:07:49.979 2020-03-07 13:07:53.763 9.5 48.82764 2.33204 0.0 paris Orange F 208 1 success e80b48a6-08c6-4b4a-b457-XXX 10.35.167.XXX 100.69.178.XXX fr SM-A600FN android 9 fr_FR custom

Quand l’on dépouille le fichier, il apparaît que chaque ligne correspond à une interaction avec l’appli ou à une réquête de l’API d’Uber. On retrouve trois type d’ “Analytics Event Type”, custom, tap et impression. Chaque déplacement de la carte, zoom, dé-zoom, ou clic est enregistré. le champ GPS Time (UTC) correspond à la date de la dernière position GPS connue. Le champ Horizontal Accuracy correspond à l’écart type sigma de position horizontale. Il est particulièrement utile pour savoir si l’utilisateur est à l’intérieur ou à l’extérieur d’un bâtiment. les champs Latitude,Longitude sont codés en degrés décimaux sur 5 décimales. les champs Carrier MCC, Carrier MNC, correspondent au code Mobile_country_code et Mobile_Network_Codes, 208 01 correspond a Orange France. le champ Device ID correspond au Google Play Services ID for Android le champ IMEI number est vide. C’est peu être un résidu de donnée qui ne sont plus collectés, ou de manière conditionnel (en l’absence de Device ID, lors de l’enregistrement).

En résumé ce fichier nous permet de tracer tout les lieux et dates d’interaction de l’utilisateur avec l’application, même si celui-ci n’effectue aucune réservation. Il nous permet aussi de savoir si il était en intérieur ou à l’extérieur, en déplacement ou statique. Si l’utilisateur utilisent plusieurs terminaux il permet aussi d’identifier les terminaux, les réseaux mobiles utilisés, leurs modèles et la version du système d’exploitation.

Je n’ai malheureusement pas de donnée pour un trajet réel (reservation, prise en charge, trajet, dépose) sur cette période confinement oblique. Je ne suis pas en mesure d’évaluer la fenêtre temporel d’enregistrement de l’application lors d’un trajet. Je n’ai pas observé d’activité dans les journaux lors que l’application n’est pas en premier plan sur le téléphone.

trips_data.csv

C’est le fichier qui contient les journaux de”détails des courses tels que les heures et lieux de demande, de début et de fin, ainsi que les distances parcourues”. Il est de structure assez simple. Voici un exemple d’un aller retour, afin de préserver ma vie privé j’ai choisit un trajet légèrement éloigné de mes lieux de travail et d’habitation.

  • City, Product Type, Trip or Order Status, Request Time, Begin Trip Time, Begin Trip Lat, Begin Trip Lng, Begin Trip Address, Dropoff Time, Dropoff Lat, Dropoff Lng Dropoff Address, Distance (miles), Fare Amount, Fare Currency
  • Cape Town UberX COMPLETED 2019-02-15 19:42:32 +0000 UTC 2019-02-15 19:44:27 +0000 UTC -33.92129 18.41808 105 Bree St, Cape Town City Centre, Cape Town, 8001, Afrique du Sud 2019-02-15 19:51:24 +0000 UTC -33.90604 18.41783 3 Portswood Rd, V & A Waterfront, Cape Town, 8002, Afrique du Sud 1.66 31 ZAR
  • Cape Town UberX COMPLETED 2019-02-15 17:28:51 +0000 UTC 2019-02-15 17:30:03 +0000 UTC -33.9060588 18.417833 3 Portswood Rd, V & A Waterfront, Cape Town, 8002, Afrique du Sud 2019-02-15 17:39:16 +0000 UTC -33.9244897 18.4195529 5 Wale St, Cape Town, 8001, ZA 1.94 40 ZAR

Chaque ligne correspond à un trajet, on retrouve les coordonnées de prise en charge Begin Trip Lat, Begin Trip Lng et de dépose Dropoff Lat, Dropoff Lng. Elles sont codées codés en degrés décimaux sur 5 décimales. Ce fichier est moins verbeux que le précédents, mais nous permet de retracer l’ensemble de l’historique de réservation de l’utilisateur. On peut noter que dans une volonté de nous faciliter l’analyse Uber nous donne les adresses postales des lieux de prise en charge et de dépose, en français. Dans cet exemple on peut facilement identifier que j’effectuais un aller retour d’un hôtel vers un restaurant.

Visualisation des données de géolocalisation

Le code pour visualiser les points d’activité utilisateur et les trajets est disponible là: https://github.com/berettavexee/Uber_map

Capture d'écran 00 Capture d'écran 01

C’est assez simple d’utilisation, il vous suffit de déposer vos fichiers rider_app_analytics-0.csv et trips_data.csv dans le sous repertoire uber et de lancer le script via python3 uber_map.py .

Conclusions

  • Il est plutôt facile d’effectuer la demande d’accès GDPR.
  • Les données fournies sont facilement exploitables.
  • Uber possède un graph des parrainage
  • Uber possède l’historique de toutes les interactions, qui inclue le dernier point de géolocalisation connue sur les 30 derniers jours.
  • Uber conserve les données techniques en mesure d’identifier tous les appareils, réseau téléphonique et réseau IP utilisés sur les 30 derniers jours.
  • Uber conserve un historique complete des trajets effectués.
  • Certaines données fournit par l’utilisateurs comme la notation des chauffeurs ou des trajets n’ont pas été transmises.

remerciements