Netflix, quelles sont vos séries préférées ? Nous allons voir comment, à l’aide de Python, déterminer vos séries préférées.

Netflix, vos séries préférées: vos données personnelles avant tout

Lorsque vous avez un compte Netflix, vous avez la possibilité de demander à la société de vous envoyer toutes les données vous concernant (c’est la loi en France). Personnellement, il m’a fallu attendre moins de 12 heures pour les recevoir. Mais un message affirme que cela peut prendre jusqu’à 30 jours… On se demande pourquoi mais si ce message est affiché, c’est qu’il y a une bonne raison (si les millions d’abonnés demandent en même temps l’envoie de leurs données personnelles, en effet, cela risque de créer un bel embouteillage numérique sur leurs serveurs).

Netflix, vos séries préférées: logo

Ces données se présentent sous la forme d’un fichier compressé au format ZIP qui, une fois décompressés, donne un dossier “netflix-report” contenant ceci:

Netflix, séries préférées: fichier décompressé

C’est dans le répertoire “CONTENT_INTERACTION” que l’on va trouver notre bonheur. En effet, c’est lui qui contient:

  • un fichier “ViewingActivity.csv” qui contient tout ce que vous avez vu sur la plateforme;
  • un fichier “Ratings.csv” qui contient vos évaluations (“je n’aime pas”, “j’aime”, “j’adore”).

Dans un premier temps, nous allons nous pencher sur le premier fichier et classer les œuvres en fonction du temps que vous avez passé à les regarder; la logique utilisée alors est celle qui consiste à affirmer que plus on passe de temps à regarder une œuvre, plus elle nous intéresse.

Netflix, vos séries préférées classées en fonction du temps de visionnage

Netflix, vos séries préférées: obtectifs du programme Python

Comme vous me connaissez peut-être à travers d’autres articles, vous vous doutez que je vais utiliser Python.

L’idée est alors la suivante:

  • on ouvre le fichier “ViewingActivity.csv”
  • à l’aide du module csv, on lit ce qu’il y a dedans (mais on n’est pas du tout obligé d’utiliser ce module pour si peu en fait…);
  • on crée un dictionnaire nommé titres dans lequel les clés seront les titres des œuvres et les valeurs, le temps total de visionnage exprimé en secondes;
  • on trie suivant les valeurs et par ordre décroissant le dictionnaire pour ainsi créer une liste ordonnée des œuvres.
  • on insère les entrées de cette liste dans un fichier txt.

Le plus chiant sera d’extraire les titres… et vous allez vite comprendre pourquoi en regardant la tête du fichier CSV initial.

Extraction des titres du fichiers CSV

Quand on ouvre le fichier “ViewingActivity.csv”, à l’aide d’un tableur (c’est beaucoup plus lisible), on voit que le format des titres diffère un peu selon que l’on regarde une série ou un film.

  • Si c’est une série, le format est: “<titre>:<saison>:<titre de l’épisode>”
  • Si c’est un film, le format est: “<titre>”

J’aimerais ne garder que le titre principal. Vous allez me dire qu’il n’y a rien de plus simple car en splitant en fonction du caractère “:”… sauf que certains titres comportent eux-mêmes des “:”… et puis, tous les titres ne sont pas aux mêmes formats! Certains comportent la mention “Saison”, “Volume’, “Season” en premier, d’autres en deuxième… Bref, c’est la merde ! Et je ne parle pas des titres qui changent de nomenclature d’une saison à l’autre (comme “Stranger things”).

Là, il a fallu pas mal de boulot… et je ne suis pas sûr d’avoir pensé à tout!

Le programme

Vous l’attendiez comme comme un cancre attend sa première bonne note, voici le programme Python:

import csv
import datetime

# fonction qui convertit les secondes en jours, heures, minutes et secondes
def convert(d):
    j = d // 86400
    h = (d - 86400*j) // 3600
    m = (d - 86400*j - 3600*h) // 60
    s = d - 86400*j - 3600*h - 60*m
    
    return j,h,m,s

# fichier CSV dans "CONTENT_INTERACTION"

f = open('ViewingActivity.csv' , encoding = 'utf8')
result = csv.reader(f)

titres = {}
c = 0
    
for liste in result:
    if c != 0:
        duree_tmp = datetime.datetime.strptime(liste[2], "%H:%M:%S")
        duree = 3600*duree_tmp.hour + 60*duree_tmp.minute + duree_tmp.second
        L_titre = liste[4].split(':')
        if len(L_titre) == 1:
            titre = liste[4]
        elif (L_titre[0] in L_titre[1]) \
             or ('Saison' in L_titre[1]) \
             or ('Mini-série' in L_titre[1]) \
             or ('Partie' in L_titre[1]) \
             or ('Volume' in L_titre[1]) \
             or ('Season' in L_titre[1]):
            title = L_titre[0]
        elif ('Saison' in L_titre[0])\
             or ('Mini-série' in L_titre[0]) \
             or ('Partie' in L_titre[0]) \
             or ('Volume' in L_titre[0]) \
             or ('Season' in L_titre[0]):
            title = L_titre[1]
        else:
            title = L_titre[0] + ':' + L_titre[1][1:]
            
        while title[0] == ' ':
            title = title[1:]
        
        if duree > 900: # si la durée dépasse 15 minutes
            if (title not in titres):
                titres[ title ] = duree
            else:
                titres[ title ] = titres[ title ] + duree

    else:
        c += 1

l_max = 0
for k,v in titres.items():
    if len(k) > l_max:
        l_max = len(k)   
l_max += 5
f = '{:.<' + str(l_max) + '} {} j {} h {} min {} s\n'

L = sorted(titres.items(), key=lambda x: x[1], reverse = True)
R = ''

for i in L:
    d = convert( i[1] )
    R += f . format(i[0],d[0],d[1],d[2],d[3])
    
f = open( 'result.txt' , 'w' , encoding='utf8' )
f.write(R)
f.close()

Ce petit programme donne pour moi un fichier texte dont les premières lignes sont les suivantes:

The Big Bang Theory.............................................. 19 j 21 h 33 min 1 s
Modern Family.................................................... 18 j 3 h 29 min 20 s
Star Trek :la nouvelle génération................................ 12 j 19 h 36 min 12 s
Brooklyn Nine-Nine............................................... 6 j 19 h 46 min 38 s
Friends.......................................................... 6 j 19 h 41 min 58 s
Dr. House........................................................ 5 j 7 h 34 min 38 s
The Walking Dead................................................. 5 j 4 h 28 min 35 s
Prison Break..................................................... 4 j 23 h 6 min 50 s
Arrow............................................................ 4 j 16 h 1 min 24 s
Blacklist........................................................ 4 j 14 h 15 min 37 s
Flash............................................................ 4 j 10 h 28 min 17 s
Mentalist........................................................ 4 j 6 h 42 min 3 s
Glee............................................................. 3 j 19 h 53 min 6 s
Grimm............................................................ 3 j 15 h 44 min 28 s
Orange Is the New Black.......................................... 3 j 14 h 14 min 30 s
Superstore....................................................... 3 j 11 h 53 min 35 s
Stranger Things.................................................. 3 j 9 h 3 min 15 s

Cela nous donne une indication des séries les plus chronophages… mais pas celles que l’on a le plus appréciées. Pour cela, il faut exploiter le fichier “Ratings.csv”.

Netflix, vos séries réellement préférées classées en fonction du temps de visionnage

Préliminaires… parce qu’il faut bien y aller doucement pour commencer…

Le fichier “ratings.csv” a le mérite d’être mieux conçu que le précédent.

En effet, il comporte le titres des œuvres sans fioritures. De plus, il y a une colonne qui nous indique:

  • si l’on a adoré (avec le nombre “3”)
  • si l’on a aimé (avec le nombre “2”)
  • si l’on a gerbé (le nombre “1”)

Mais ça, c’est avec la nouvelle notation (avec les pouces)… car pour les anciens, on se souvient qu’au début, on notait avec des étoiles (de 1 à 5 étoiles). Il faudra donc décider d’une correspondance, comme par exemple:

  • 1 ou 2 étoiles : à gerber !
  • 2, 3 ou 4 étoiles: on a aimé
  • 5 étoiles: on a adoré !

Il faut aussi penser au fait que l’on peut avoir noté une série avec les deux systèmes… dans ce cas, seul le nouveau système (le plus récent) comptera.

Voici alors le programme:

import csv

# fichier CSV dans "CONTENT_INTERACTION"

f = open('Ratings.csv' , encoding = 'utf8')
result = csv.reader(f)

c = 0
titres = {}

for liste in result:
    if c == 0:
        c += 1
    else:
        if liste[1] not in titres:
            if liste[2] == 'thumb':
                titres[ liste[1] ] = int( liste[4] )
            else:
                if (liste[4] == '4') or (liste[4] == '3'):
                    titres[ liste[1] ] = 2
                elif (liste[4] == '5'):
                    titres[ liste[1] ] = 3
                else:
                    titres[ liste[1] ] = 1

L = sorted(titres.items(), key=lambda x: x[1], reverse = True)

R = 'Adoration maximale\n' + '-'*18 + '\n\n'

c = 0
for i in L:
    if i[1] == 2 and c == 0:
        R += '\n\nOn a bien aimé' + '-'*14 + '\n\n'
        c = 1
    elif i[1] == 1 and c == 1:
        R += '\n\'À gerber' + '-'*8 + '\n\n'
        c = 2
        
    R += '{}\n' . format(i[0])
    
f = open( 'favoris.txt' , 'w' , encoding='utf8' )
f.write(R)
f.close()

Le fichier texte que j’ai obtenu commence par:

Adoration maximale
------------------

The Green Mile
Sweet Tooth
Time Trap
Sexify
Making a Murderer
Santa Clarita Diet
Murdaugh Murders: A Southern Scandal
MH370: The Plane That Disappeared
The Good Place
We Have a Ghost
That '90s Show
Pulp Fiction
Alice in Borderland
1899
Dark
Men in Black: International
The Girl in the Mirror
DAHMER
Loving Adults
The Sandman
Brooklyn Nine-Nine
The Secret Life of Pets 2
Something to Hide
Brightburn
The Umbrella Academy
Stranger Things
The 7 Lives of Lea
Heartstopper
The Pentaverate
The Curse of La Llorona


On a bien aimé--------------

The Keepers
Safe
Crime Scene: The Texas Killing Fields
...

Le programme complet

Le fichier est bien, mais j’aimerais maintenant bel et bien classer les titres que j’ai adoré en fonction du temps que j’ai passé à regarder ces œuvres. Vous sentez arriver la partouse numérique ? On va mélanger les deux scripts précédents et ça va être génial!

import csv
import datetime

"""
Fonction: retourne la liste des films/séries avec leur notes
"""
def favorite():
    f = open('Ratings.csv' , encoding = 'utf8')
    result = csv.reader(f)

    c = 0
    titres = {}
       
    for liste in result:
        if c == 0:
            c += 1
        else:
            if liste[1] not in titres:
                if liste[2] == 'thumb':
                    titres[ liste[1] ] = int( liste[4] )
                else:
                    if (liste[4] == '4') or (liste[4] == '3'):
                        titres[ liste[1] ] = 2
                    elif (liste[4] == '5'):
                        titres[ liste[1] ] = 3
                    else:
                        titres[ liste[1] ] = 1

    return titres


"""
Fonction: conversion des secondes en j,h,m,s
"""
def convert(d):
    j = d // 86400
    h = (d - 86400*j) // 3600
    m = (d - 86400*j - 3600*h) // 60
    s = d - 86400*j - 3600*h - 60*m
    
    return j,h,m,s

"""
Fonction: retourne la liste des titres et du temps passé
"""
def chrono():
    f = open('ViewingActivity.csv' , encoding = 'utf8')
    result = csv.reader(f)

    titres = {}
    c = 0
        
    for liste in result:
        if c != 0:
            duree_tmp = datetime.datetime.strptime(liste[2], "%H:%M:%S")
            duree = 3600*duree_tmp.hour + 60*duree_tmp.minute + duree_tmp.second
            L_titre = liste[4].split(':')
            if len(L_titre) == 1:
                titre = liste[4]
            elif (L_titre[0] in L_titre[1]) \
                 or ('Saison' in L_titre[1]) \
                 or ('Mini-série' in L_titre[1]) \
                 or ('Partie' in L_titre[1]) \
                 or ('Volume' in L_titre[1]) \
                 or ('Season' in L_titre[1]):
                title = L_titre[0]
            elif ('Saison' in L_titre[0])\
                 or ('Mini-série' in L_titre[0]) \
                 or ('Partie' in L_titre[0]) \
                 or ('Volume' in L_titre[0]) \
                 or ('Season' in L_titre[0]):
                title = L_titre[1]
            else:
                title = L_titre[0] + ':' + L_titre[1][1:]
                
            while title[0] == ' ':
                title = title[1:]
            
            if duree > 900: # si la durée dépasse 15 minutes
                if (title not in titres):
                    titres[ title ] = duree
                else:
                    titres[ title ] = titres[ title ] + duree

        else:
            c += 1

    return sorted(titres.items(), key=lambda x: x[1], reverse = True)

"""
Programe principal
"""

if __name__ == "__main__":
    F = favorite() # dictionnaire
    C = chrono() # liste ordonnée décroissante sur le temps
    G = {}
    failed = []

    for titre in C:
        if titre[0] in F:
            G[ titre[0] ] = ( F[ titre[0] ] , titre[1])
        else:
            failed.append( titre[0] )
            
    list_of_greatests = []
    list_of_likes = []
    list_of_beurks = []
    
    for t,v in G.items():
        if v[0] == 3:
            list_of_greatests.append( (t,v[1]) )
        elif v[0] == 2:
            list_of_likes.append( (t,v[1]) )
        else:
            list_of_beurks.append( (t,v[1]) )
            
    R = 'On a adoré:\n----------\n'
    
    l_max = 0
    for i in list_of_greatests:
        if len(i[0]) > l_max:
            l_max = len(i[0])   
    l_max += 5
    f = '{:.<' + str(l_max) + '} {} j {} h {} min {} s\n'
    for i in list_of_greatests:
        d = convert( i[1] )
        R += f . format(i[0],d[0],d[1],d[2],d[3])
    
    R += '\n\nOn a aimé:\n---------\n'
    
    l_max = 0
    for i in list_of_likes:
        if len(i[0]) > l_max:
            l_max = len(i[0])   
    l_max += 5
    f = '{:.<' + str(l_max) + '} {} j {} h {} min {} s\n'
    for i in list_of_likes:
        d = convert( i[1] )
        R += f . format(i[0],d[0],d[1],d[2],d[3])
        
    R += '\n\nOn a gerbé pour:\n----------------\n'
    
    l_max = 0
    for i in list_of_beurks:
        if len(i[0]) > l_max:
            l_max = len(i[0])   
    l_max += 5
    f = '{:.<' + str(l_max) + '} {} j {} h {} min {} s\n'
    for i in list_of_beurks:
        d = convert( i[1] )
        R += f . format(i[0],d[0],d[1],d[2],d[3])
        
    f = open( 'ultimate.txt' , 'w' , encoding='utf8' )
    f.write(R)
    f.close()

Le fichier texte que j’obtiens est:

On a adoré:
----------
The Big Bang Theory..... 19 j 21 h 33 min 1 s
Brooklyn Nine-Nine...... 6 j 19 h 46 min 38 s
Stranger Things......... 3 j 9 h 3 min 15 s
The Good Place.......... 2 j 21 h 15 min 57 s
Dark.................... 2 j 5 h 30 min 14 s
Santa Clarita Diet...... 1 j 21 h 3 min 18 s
Alice in Borderland..... 0 j 21 h 44 min 27 s
Making a Murderer....... 0 j 20 h 57 min 5 s
Sweet Tooth............. 0 j 17 h 53 min 47 s
Sexify.................. 0 j 11 h 44 min 47 s
Heartstopper............ 0 j 6 h 50 min 27 s
1899.................... 0 j 6 h 43 min 50 s
That '90s Show.......... 0 j 3 h 39 min 49 s
The Pentaverate......... 0 j 2 h 29 min 23 s


On a aimé:
---------
Modern Family....................... 18 j 3 h 29 min 20 s
Friends............................. 6 j 19 h 41 min 58 s
Prison Break........................ 4 j 23 h 6 min 50 s
Arrow............................... 4 j 16 h 1 min 24 s
...

Ce script n’est pour autant pas optimal car… Netflix a eut la géniale idée de ne pas coder ses titres de la même façon dans les deux fichiers! Quelle bande de nulos ! Il y a donc énormément de titres qui se retrouvent relégués en dernier.

Il faut donc écrire une fonction qui compare deux titres. Pour cela, on peut spliter deux titres et regarder si, par exemple, 50% des mots d’une liste apparaît dans l’autre (sans oublier de ne considérer que les chaines mises en minuscule et sans accent).

def search(titre, dico , seuil = 0.5):
    for t in dico.keys():
        L_t = t.split()
        L_titre = unidecode(titre.lower()).split()
        compteur = 0
        for i in L_t:
            if unidecode( i.replace(':','').lower() ) in L_titre:
                compteur += 1
                
        if (compteur/len(L_t) >= seuil):
            return (compteur/len(L_t) >= seuil , t)
        
    return (False,0)

On peut bien entendu changer le seuil de 50% si cela ne convient pas. Mais pour moi, ça le fait!

Les abonné·e·s de ce site trouveront le programme Python complet ci-dessous:

On a adoré:
----------
The Big Bang Theory......................... 19 j 21 h 33 min 1 s
Brooklyn Nine-Nine.......................... 6 j 19 h 46 min 38 s
Stranger Things............................. 3 j 9 h 3 min 15 s
That '70s Show.............................. 3 j 6 h 56 min 29 s
The Good Place.............................. 2 j 21 h 15 min 57 s
Dark........................................ 2 j 5 h 30 min 14 s
Santa Clarita Diet.......................... 1 j 21 h 3 min 18 s
Umbrella Academy............................ 1 j 18 h 58 min 22 s
Alice in Borderland......................... 0 j 21 h 44 min 27 s
Making a Murderer........................... 0 j 20 h 57 min 5 s
Sweet Tooth................................. 0 j 17 h 53 min 47 s
Sexify...................................... 0 j 11 h 44 min 47 s
Sandman..................................... 0 j 11 h 6 min 48 s
Heartstopper................................ 0 j 6 h 50 min 27 s
1899........................................ 0 j 6 h 43 min 50 s
That '90s Show.............................. 0 j 3 h 39 min 49 s
Keep Sweet :Prie et tais-toi................ 0 j 3 h 4 min 37 s
Jeffrey Dahmer :Autoportrait d'un tueur..... 0 j 2 h 50 min 48 s
The Pentaverate............................. 0 j 2 h 29 min 23 s
Men in Black:International.................. 0 j 1 h 45 min 15 s
Teaser :Me Time ............................ 0 j 1 h 23 min 21 s
Bande-annonce :One More Time................ 0 j 1 h 17 min 1 s
1899 :Le making-of.......................... 0 j 0 h 43 min 40 s

Il y a plus de titres qui correspondent en effet à ce que j’ai adoré.

Catégories : Python

0 0 votes
Évaluation de l'article
S’abonner
Notification pour
guest
0 Commentaires
Le plus ancien
Le plus récent Le plus populaire
Commentaires en ligne
Afficher tous les commentaires
0
Nous aimerions avoir votre avis, veuillez laisser un commentaire.x