Cómo aplicar una función a dos columnas del marco de datos de Pandas

Resuelto bigbug asked hace 12 años • 0 respuestas

Supongamos que tengo una función y un marco de datos definidos como se muestra a continuación:

def get_sublist(sta, end):
    return mylist[sta:end+1]

df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']

Ahora quiero aplicar get_sublista dflas dos columnas 'col_1', 'col_2'de para calcular por elementos una nueva columna 'col_3'para obtener un resultado que se vea así:

  ID  col_1  col_2            col_3
0  1      0      1       ['a', 'b']
1  2      2      4  ['c', 'd', 'e']
2  3      3      5  ['d', 'e', 'f']

Lo intenté

df['col_3'] = df[['col_1','col_2']].apply(get_sublist, axis=1)

pero esto resulta en

TypeError: get_sublist() missing 1 required positional argument:

¿Cómo lo hago?

bigbug avatar Nov 11 '12 20:11 bigbug
Aceptado

Hay una manera clara y de una sola línea de hacer esto en Pandas:

df['col_3'] = df.apply(lambda x: f(x.col_1, x.col_2), axis=1)

Esto permite fser una función definida por el usuario con múltiples valores de entrada y utiliza nombres de columnas (seguros) en lugar de índices numéricos (inseguros) para acceder a las columnas.

Ejemplo con datos (basado en la pregunta original):

import pandas as pd

df = pd.DataFrame({'ID':['1', '2', '3'], 'col_1': [0, 2, 3], 'col_2':[1, 4, 5]})
mylist = ['a', 'b', 'c', 'd', 'e', 'f']

def get_sublist(sta,end):
    return mylist[sta:end+1]

df['col_3'] = df.apply(lambda x: get_sublist(x.col_1, x.col_2), axis=1)

Salida de print(df):

  ID  col_1  col_2      col_3
0  1      0      1     [a, b]
1  2      2      4  [c, d, e]
2  3      3      5  [d, e, f]

Si los nombres de sus columnas contienen espacios o comparten un nombre con un atributo de marco de datos existente, puede indexar con corchetes:

df['col_3'] = df.apply(lambda x: f(x['col 1'], x['col 2']), axis=1)
ajrwhite avatar Oct 17 '2018 12:10 ajrwhite

Aquí hay un ejemplo que utiliza applyel marco de datos, al que estoy llamando axis = 1.

Tenga en cuenta que la diferencia es que en lugar de intentar pasar dos valores a la función f, reescriba la función para aceptar un objeto de la Serie pandas y luego indexe la Serie para obtener los valores necesarios.

In [49]: df
Out[49]: 
          0         1
0  1.000000  0.000000
1 -0.494375  0.570994
2  1.000000  0.000000
3  1.876360 -0.229738
4  1.000000  0.000000

In [50]: def f(x):    
   ....:  return x[0] + x[1]  
   ....:  

In [51]: df.apply(f, axis=1) #passes a Series object, row-wise
Out[51]: 
0    1.000000
1    0.076619
2    1.000000
3    1.646622
4    1.000000

Dependiendo de su caso de uso, a veces es útil crear un groupobjeto pandas y luego usarlo applyen el grupo.

Aman avatar Nov 12 '2012 01:11 Aman

Una solución sencilla es:

df['col_3'] = df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)
sjm avatar Aug 31 '2016 21:08 sjm

¡Una pregunta interesante! mi respuesta es la siguiente:

import pandas as pd

def sublst(row):
    return lst[row['J1']:row['J2']]

df = pd.DataFrame({'ID':['1','2','3'], 'J1': [0,2,3], 'J2':[1,4,5]})
print df
lst = ['a','b','c','d','e','f']

df['J3'] = df.apply(sublst,axis=1)
print df

Producción:

  ID  J1  J2
0  1   0   1
1  2   2   4
2  3   3   5
  ID  J1  J2      J3
0  1   0   1     [a]
1  2   2   4  [c, d]
2  3   3   5  [d, e]

Cambié el nombre de la columna a ID, J1, J2, J3 para garantizar que ID <J1 <J2 <J3, de modo que la columna se muestre en la secuencia correcta.

Una versión breve más:

import pandas as pd

df = pd.DataFrame({'ID':['1','2','3'], 'J1': [0,2,3], 'J2':[1,4,5]})
print df
lst = ['a','b','c','d','e','f']

df['J3'] = df.apply(lambda row:lst[row['J1']:row['J2']],axis=1)
print df
 avatar Apr 24 '2015 02:04

El método que estás buscando es Series.combine. Sin embargo, parece que se debe tener cierto cuidado con los tipos de datos. En su ejemplo, usted (como lo hice yo al probar la respuesta) llamaría ingenuamente

df['col_3'] = df.col_1.combine(df.col_2, func=get_sublist)

Sin embargo, esto arroja el error:

ValueError: setting an array element with a sequence.

Mi mejor suposición es que parece esperar que el resultado sea del mismo tipo que la serie que llama al método (df.col_1 aquí). Sin embargo, lo siguiente funciona:

df['col_3'] = df.col_1.astype(object).combine(df.col_2, func=get_sublist)

df

   ID   col_1   col_2   col_3
0   1   0   1   [a, b]
1   2   2   4   [c, d, e]
2   3   3   5   [d, e, f]
JoeCondron avatar Mar 05 '2015 15:03 JoeCondron