Crear nuevas columnas iterando sobre filas en el marco de datos de pandas

10

Tengo un marco de datos de pandas (X11) como este: en realidad tengo 99 columnas hasta 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

Quiero crear columnas adicionales para valores de celda como 25041,40391,5856, etc. Entonces habrá una columna 25041 con un valor de 1 o 0 si 25041 aparece en esa fila en particular en cualquier columna dxs. Estoy usando este código y funciona cuando el número de filas es menor.

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)

Estoy obteniendo un resultado como este:

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

Cuando el número de filas es de muchos miles o millones, se cuelga y tarda una eternidad y no obtengo ningún resultado. Observe que los valores de las celdas no son exclusivos de la columna, sino que se repiten en varias columnas. Por ejemplo, 40391 está ocurriendo en dx1 así como en dx2 y así sucesivamente para 0 y 5856, etc. ¿Alguna idea de cómo mejorar la lógica mencionada anteriormente?

Sanoj
fuente
Alguna idea de como resolver esto? Todavía estoy esperando que esto se resuelva a medida que mis datos se vuelven cada vez más grandes y la solución existente toma para siempre columnas ficticias generadas.
Sanoj

Respuestas:

6

Hay una solución mucho más pitónica en los pandas ...

Esto toma menos de un segundo en 10 millones de filas en mi computadora portátil:

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

Aquí están los detalles establecidos:

Marco de datos pequeño y 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

marco de datos pequeño y simple

Método de binarización

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

ingrese la descripción de la imagen aquí

Marco de datos con 10 millones de filas:

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

ingrese la descripción de la imagen aquí

Binarización cronometrada (también conocida como codificación de uno en caliente) en el marco de datos de 10 millones de filas:

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

ingrese la descripción de la imagen aquí

¡Espero que esto ayude!

AN6U5
fuente
Esto no dice cómo obtendrá dinámicamente el valor ficticio (25041) y los nombres de columna (es decir, dx1) en el bucle for. Solo puedo obtener uno a la vez.
Sanoj
Echa un vistazo ahora. Agregué todos los detalles.
AN6U5
Su solución se ve bien si necesito crear valores ficticios basados ​​en una columna solo como lo ha hecho desde "E". Pero cuando tengo que crearlo a partir de varias columnas y esos valores de celda no son exclusivos de una columna en particular, ¿necesito repetir su código para todas esas columnas? Si ese es el caso, ¿cómo se resolverá la repetición de valores? De lo contrario, sobrescribirá la columna ficticia anterior creada con el mismo nombre. He agregado mi resultado en la pregunta anterior para dejar en claro si hubo alguna confusión. Gracias de todos modos por haberlo investigado.
Sanoj
4

Parece que desea crear una variable ficticia a partir de una columna de marco de datos de pandas. Afortunadamente, los pandas tiene un método especial para ello: get_dummies(). Aquí hay un fragmento de código que puede adaptar a sus necesidades:

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]

Aquí está la salida 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
fuente
Se ve bien, pero si lo ve con cuidado, encontrará que para value_0, no tiene 1 en todas las filas. Como 0 está presente en todas las filas, por lo tanto, value_0 debería tener 1 en todas las filas. Lo mismo para value_5856, Value_25081, etc. Parece que esta lógica es elegir valores de una columna y luego no retroceder, sino avanzar.
Sanoj
Hola sanoj No es realmente justo usar mi solución y rechazarme. Lo menos que puede hacer es actualizar su pregunta con el nuevo progreso que realizó en lugar de abrir una nueva pregunta. Si quieres que la gente te ayude, debes jugar bien con ellos.
michaelg
Hola michaeld: no tenía intención de rechazarte. Acabo de quitar el signo de clic ya que esta solución no satisfizo mis necesidades como se hizo en la pregunta. Inicialmente pensé que estaba bien, pero luego, cuando investigué, encontré las discrepancias mencionadas en la respuesta anterior. No recibía ninguna respuesta de esto, por lo tanto, creé una nueva pregunta donde mencioné mi respuesta original e incluí su respuesta con la corrección necesaria. Lo siento, no mencioné tu nombre allí. Lo actualizaré.
Sanoj