Création de nouvelles colonnes en itérant sur les lignes dans la trame de données pandas

10

J'ai une trame de données pandas (X11) comme celle-ci: en réalité, j'ai 99 colonnes jusqu'à dx99

    dx1      dx2    dx3    dx4
0   25041   40391   5856    0
1   25041   40391   25081   5856
2   25041   40391   42822   0
3   25061   40391   0       0
4   25041   40391   0       5856
5   40391   25002   5856    3569

Je veux créer des colonnes supplémentaires pour des valeurs de cellule comme 25041,40391,5856 etc. Il y aura donc une colonne 25041 avec la valeur 1 ou 0 si 25041 se produit dans cette ligne particulière dans les colonnes dxs. J'utilise ce code et cela fonctionne lorsque le nombre de lignes est inférieur.

mat = X11.as_matrix(columns=None)
values, counts = np.unique(mat.astype(str), return_counts=True)

for x in values:
    X11[x] = X11.isin([x]).any(1).astype(int)

J'obtiens un résultat comme celui-ci:

dx1     dx2     dx3    dx4  0   25002   25041   25061   25081   3569    40391   42822   5856
25041   40391   5856    0   0   0       1       0       0       0          1        0       1
25041   40391   25081  5856 0   0       1       0       1       0            1      0       1
25041   40391   42822   0   0   0       1       0       0       0           1       1       0
25061   40391   0       0   0   0       0       1       0       0          1        0       0
25041   40391   0    5856   0   0       1       0       0       0          1        0       1
40391   25002 5856   3569   0   1       0       0       0       1          1        0       1

Lorsque le nombre de lignes est de plusieurs milliers ou de millions, cela se bloque et prend une éternité et je n'obtiens aucun résultat. Veuillez noter que les valeurs des cellules ne sont pas uniques à la colonne, mais plutôt répétées dans plusieurs colonnes. Par exemple, 40391 se produit dans dx1 ainsi que dans dx2 et ainsi de suite pour 0 et 5856 etc. Une idée comment améliorer la logique mentionnée ci-dessus?

Sanoj
la source
Aucune idée sur la façon de résoudre ça? J'attends toujours que cela se résolve car mes données deviennent de plus en plus grandes et la solution existante prend pour toujours des colonnes factices générées.
Sanoj

Réponses:

6

Il y a une solution beaucoup plus pythonique dans les pandas ...

Cela prend moins d'une seconde sur 10 millions de lignes sur mon ordinateur portable:

for x in X11.E.unique():
    X11[x]=(X11.E==x).astype(int)
X11

Voici les détails présentés:

Petite trame de données simple -

import numpy as np
import pandas as pd

X11 = pd.DataFrame(np.random.randn(6,4), columns=list('ABCD'))
X11['E'] = [25223, 112233,25223,14333,14333,112233]
X11

petite trame de données simple

Méthode de binarisation -

for x in X11.E.unique():
    X11[x]=(X11.E==x).astype(int)
X11

entrez la description de l'image ici

Cadre de données avec 10 millions de lignes -

pd.set_option("display.max_rows",20)
X12 = pd.DataFrame(np.random.randn(10000000,4), columns=list('ABCD'))
foo = [25223, 112233,25223,14333,14333,112233]
bar=[]
import random
for x in range(10000000):
    bar.append(random.choice(foo))
X12['E'] = bar
X12

entrez la description de l'image ici

Binarisation temporisée (aka codage à chaud) sur 10 millions de lignes de données -

import time
start = time.clock()

for x in X12.E.unique():
    X12[x]=(X12.E==x).astype(int)
elapsed = (time.clock() - start)

print "This is the time that this took in seconds: ",elapsed

X12

entrez la description de l'image ici

J'espère que cela t'aides!

AN6U5
la source
Cela ne dit pas comment vous obtiendrez dynamiquement la valeur fictive (25041) et les noms de colonne (c'est-à-dire dx1) dans la boucle for. Je ne peux en obtenir qu'un à la fois.
Sanoj
Jetez un oeil maintenant. J'ai ajouté tous les détails.
AN6U5
Votre solution semble bonne si j'ai besoin de créer des valeurs fictives basées sur une seule colonne comme vous l'avez fait à partir de "E". Mais quand je dois le créer à partir de plusieurs colonnes et que ces valeurs de cellule ne sont pas uniques à une colonne particulière, dois-je boucler à nouveau votre code pour toutes ces colonnes? Si tel est le cas, comment la répétition des valeurs sera-t-elle gérée? Sinon, il écrasera la colonne factice précédente créée avec le même nom. J'ai ajouté mon résultat à la question ci-dessus pour indiquer clairement s'il y avait une confusion. Merci quand même pour votre recherche.
Sanoj
4

Il semble que vous souhaitiez créer une variable fictive à partir d'une colonne de trame de données pandas. Heureusement, a Pandas une méthode spéciale pour elle: get_dummies(). Voici un extrait de code que vous pouvez adapter à vos besoins:

import pandas as pd
data = pd.read_clipboard(sep=',')

#get the names of the first 3 columns
colN = data.columns.values[:3]

#make a copy of the dataframe
data_transformed = data

#the get_dummies method is doing the job for you
for column_name in colN:
    dummies = pd.get_dummies(data_transformed[column_name], prefix='value', prefix_sep='_')
    col_names_dummies = dummies.columns.values

    #then you can append new columns to the dataframe
    for i,value in enumerate(col_names_dummies):
        data_transformed[value] = dummies.iloc[:,i]

Voici la sortie de data_transformed:

         dx1    dx2    dx3   dx4    dx5    dx6    dx7  value_25041  value_25061  0  25041  40391   5856     0  V4511  V5867  30000            1            0   
    1  25041  40391  25081  5856   5363   3572      0            1            0   
    2  25041  40391  42822     0   5856      0      0            1            0   
    3  25061  40391      0     0      0      0      0            0            1   
    4  25041  40391      0  5856  25081  V4511  25051            1            0   

      value_40391  value_0  value_5856  value_25081  value_42822  
    0            1        0           1            0            0  
    1            1        0           0            1            0  
    2            1        0           0            0            1  
    3            1        1           0            0            0  
    4            1        1           0            0            0  
michaelg
la source
Il semble correct, mais si vous voyez attentivement, vous constaterez que pour value_0, il n'a pas 1 dans toutes les lignes. Puisque 0 est présent dans toutes les lignes, value_0 devrait donc avoir 1 dans toutes les lignes. Idem pour value_5856, Value_25081 etc. Il semble que cette logique sélectionne des valeurs dans une colonne et ne recule pas à la place pour avancer.
Sanoj
Salut Sanoj. Ce n'est pas vraiment juste d'utiliser ma solution et de me voter contre. Le moins que vous puissiez faire est de mettre à jour votre question avec les nouveaux progrès que vous avez faits au lieu d'ouvrir une nouvelle question. Si vous voulez que les gens vous aident, vous devriez jouer bien avec eux.
michaelg
Bonjour michaeld: Je n'avais pas l'intention de vous voter contre. Je viens de retirer le signe de clic car cette solution ne répondait pas à mes besoins comme demandé en question. Au début, je pensais bien, mais plus tard, lorsque j'ai enquêté, j'ai trouvé les écarts comme mentionné dans la réponse ci-dessus. Je n'obtenais aucune réponse à cela, j'ai donc créé une nouvelle question où j'ai mentionné ma réponse d'origine et inclus votre réponse avec la correction nécessaire. Désolé, je n'ai pas mentionné votre nom ici. Je vais le mettre à jour.
Sanoj