IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Optimisation de boucles en pandas [Python 2.X]


Sujet :

Python

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 147
    Par défaut Optimisation de boucles en pandas
    Bonjour à tous,

    Je travaille actuellement en machine learning, dans lequel je peux intégrer du code python (langage que j'apprends en autodidacte)

    Je vous explique ma problématique :

    En entrée de mon code python, deux dataframes :

    Mon dataframe1, qui contient 2 colonnes : ID client, et une probabilité prob_forest associée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ID       prob_forest
    123         0.002
    456         0.998
    ...             ...
    La taille de ce fichier est variable (100 000 à plusieurs millions de lignes)

    Dans mon dataframe2, 3 colonnes : prob_forest_quantized (centile d'une probabilité prob_forest), min et max, respectivement les bornes des probabilités sur le centile concerné :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    prob_forest_quantized  min      max
    1                               0        0.012
    2                             0.013    0.078
    ...
    100                         0.962       1
    Ce dataframe fera toujours au maximum 100 lignes

    En sortie de ce code, j'aimerais obtenir mon dataframe1 enrichi de prob_forest_quantized en fonction des bornes du dataframe2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ID       prob_forest     prob_forest_quantized
    123         0.002                  1
    456         0.998                  100
    ...             ...                     ...
    Pour cela, j'ai créé le code Python suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    def aml_main(dataframe1, dataframe2):
    #longueur des tables
           l1=len(dataframe1)
           l2=len(dataframe2)
     
        # Initialisation
           dataframe1.loc[:,"prob_forest_quantized"]=0
     
        # pour chaque ligne du df1
           for i in xrange(l1):
                  # Pour chaque ligne du df2
                  for j in xrange(l2) :
                         # Si la valeur de la probabilité dans df1 est comprise entre les bornes min et max de la ligne j de df2
                         if dataframe1.loc[i, "prob_forest"]>=dataframe2.loc[j,"min"] and dataframe1.loc[i, "prob_forest"]<= dataframe2.loc[j, "max"] :
                                # définir la variable prob_forest_quantized de df1 avec la valeur de prob_forest_quantized de la ligne j de df2
                                dataframe1.loc[i, "prob_forest_quantized"]=dataframe2.loc[j,"prob_forest_quantized"]
    Celui-ci fonctionne, mais avec les deux boucles + le if, c'est très long à tourner (ça tourne depuis actuellement 3h sur 4 codes Python en parallèle, sur un dataframe1 de 100 000 lignes).

    Vous serait-il possible de m'aider à optimiser ce code? (grâce à des fonctions peut-être...)

    Merci d'avance pour votre aide!

    Bonne journée

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Je ne connais pas vraiment pandas, mais en me basant sur ce que je ferais en numpy, j'arrive à ceci dont tu devrais pouvoir t'inspirer:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    >>> import numpy as np
    >>> import pandas as pd
    >>> df1 = pd.DataFrame(np.random.randn(10,1), columns=["x"])
    >>> df1
              x
    0 -1.040534
    1  1.431923
    2 -2.430330
    3  0.004224
    4  0.924767
    5  0.846549
    6 -0.412876
    7 -0.218280
    8  0.243771
    9  0.232233
     
    [10 rows x 1 columns]
    >>> df2 = pd.DataFrame([[-3,-2],[-2,-1],[-1,0],[0,1],[1,2],[2,3]],columns=("min","max"))
    >>> df2
       min  max
    0   -3   -2
    1   -2   -1
    2   -1    0
    3    0    1
    4    1    2
    5    2    3
     
    [6 rows x 2 columns]
    >>> for i,(min,max) in df2.iterrows():
            df1.loc[(df1["x"] >= min) & (df1["x"] < max),"quant"] = i
     
    >>> df1
              x  quant
    0 -1.040534      1
    1  1.431923      4
    2 -2.430330      0
    3  0.004224      3
    4  0.924767      3
    5  0.846549      3
    6 -0.412876      2
    7 -0.218280      2
    8  0.243771      3
    9  0.232233      3
     
    [10 rows x 2 columns]
    La seule boucle explicite est sur les lignes du second DataFrame (le plus petit), le reste est vectorisé par pandas/numpy.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 147
    Par défaut
    Merci! Je vais tester ça

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Probablement encore mieux, en utilisant numpy.digitize:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    >>> import numpy as np
    >>> import pandas as pd
    >>> df1 = pd.DataFrame(np.random.randn(10,1), columns=["x"])
    >>> df2 = pd.DataFrame([[1,-3,-2],[2,-2,-1],[3,-1,0],[4,0,1],[5,1,2],[6,2,3]],columns=("prob","min","max"))
    >>> df1.ix[:,"quant"] = df2.ix[np.digitize(df1["x"], df2["max"],right=True),"prob"].values
    >>> df1
              x  quant
    0 -1.410299      2
    1 -1.205431      2
    2  1.313114      5
    3  1.616724      5
    4  1.272656      5
    5 -0.366515      3
    6 -0.837589      3
    7 -0.294710      3
    8  0.838563      4
    9 -0.522777      3
     
     
    [10 rows x 2 columns]
    Comme seule la colonne "max" de df2 est utilisée, j'ai mis "right=True" dans l'appel de digitize, ça semblait mieux coller avec les données que tu as postées.

  5. #5
    Membre éclairé
    Homme Profil pro
    Amateur
    Inscrit en
    Juin 2015
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : Amateur
    Secteur : Transports

    Informations forums :
    Inscription : Juin 2015
    Messages : 52
    Par défaut
    Tu pourrais utiliser la fonction cut de pandas. En reprenant l'exemple de dividee

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    >>> df1 = pd.DataFrame(np.random.randn(10,1), columns=["x"])
    >>> df2 = pd.DataFrame([[1,-3,-2],[2,-2,-1],[3,-1,0],[4,0,1],[5,1,2],[6,2,3]],columns=("prob","min","max"))
    >>> bins = df2['min'].append(df2['max'].tail(1)) # On ajoute le max du dernier élément pour avoir tous nos bins
    >>> bins
    0   -3
    1   -2
    2   -1
    3    0
    4    1
    5    2
    5    3
    >>> df1["quant"] = pd.cut(df1['x'], bins=bins, labels=df2['prob'])
    >>> df1
              x quant
    0  0.488248     4
    1 -1.262740     2
    2  1.928657     5
    3  0.773359     4
    4 -1.214497     2
    5 -0.939815     3
    6  0.398891     4
    7 -2.561159     1
    8 -1.210615     2
    9  0.950369     4

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 147
    Par défaut
    Hello,

    Tout d'abord, merci pour vos réponses.
    J'ai travaillé sur la première réponse de dividee, et ça fonctionne parfaitement!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #       dataframe1.loc[:,"prob_forest_quantized"]=0
           dataframe2 = dataframe2.set_index('prob_forest_quantized')
     
           for i, (min,max) in dataframe2.iterrows():
                  dataframe1.loc[(dataframe1["prob_forest"] >= min) & (dataframe1["prob_forest"] < max),"prob_forest_quantized"] = i
    Je passe le sujet en mais je vais quand même tester les autres réponses.
    Merci encore

    Milou

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment optimiser plusieurs boucles FOR-END imbriquées
    Par totoc1001 dans le forum MATLAB
    Réponses: 26
    Dernier message: 13/05/2007, 17h59
  2. [Tableaux] Optimisation de boucles
    Par xdoreau dans le forum Langage
    Réponses: 4
    Dernier message: 12/02/2007, 11h28
  3. Optimisation de boucle 'while..do'
    Par delphi5user dans le forum Delphi
    Réponses: 10
    Dernier message: 25/07/2006, 22h37
  4. Probleme optimisation de boucles
    Par panda31 dans le forum C
    Réponses: 13
    Dernier message: 06/04/2006, 15h10
  5. Réponses: 4
    Dernier message: 17/01/2006, 19h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo