Supongamos que tengo un df
que tiene columnas de 'ID', 'col_1', 'col_2'
. Y defino una función:
f = lambda x, y : my_function_expression
.
Ahora quiero aplicar la f
a df
's dos columnas 'col_1', 'col_2'
para calcular elemento gota una nueva columna 'col_3'
, algo así como:
df['col_3'] = df[['col_1','col_2']].apply(f)
# Pandas gives : TypeError: ('<lambda>() takes exactly 2 arguments (1 given)'
Cómo hacer ?
** ** Agregue una muestra detallada como a continuación ***
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[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below
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']
f
está haciendoRespuestas:
Aquí hay un ejemplo de uso
apply
en el marco de datos, con el que estoy llamandoaxis = 1
.Tenga en cuenta que la diferencia es que, en lugar de tratar de pasar dos valores a la función
f
, reescriba la función para aceptar un objeto Serie pandas y luego indexe la Serie para obtener los valores necesarios.Dependiendo de su caso de uso, a veces es útil crear un
group
objeto pandas y luego usarloapply
en el grupo.fuente
sum
se resuelve con éxito mediante cualquiera de los métodos sugeridos hasta ahora.df
objeto que definiste, otro enfoque (con resultados equivalentes) esdf.apply(lambda x: x[0] + x[1], axis = 1)
.Hay una forma limpia y de una línea de hacer esto en Pandas:
Esto permite
f
ser una función definida por el usuario con múltiples valores de entrada y utiliza nombres de columna (seguros) en lugar de índices numéricos (inseguros) para acceder a las columnas.Ejemplo con datos (basado en la pregunta original):
Salida de
print(df)
:Si los nombres de sus columnas contienen espacios o comparten un nombre con un atributo de marco de datos existente, puede indexar entre corchetes:
fuente
axis=1
y se llamaname
su columna, en realidad no devolverá los datos de su columna, sino elindex
. Similar a obtener elname
en agroupby()
. Resolví esto cambiando el nombre de mi columna..loc
en el ejemplo. Puede ser necesario si adapta esto a otra configuración del problema (por ejemplo, trabajar con sectores).Una solución simple es:
fuente
Una pregunta interesante! mi respuesta de la siguiente manera:
Salida:
Cambié el nombre de la columna a ID, J1, J2, J3 para asegurar ID <J1 <J2 <J3, por lo que la columna se muestra en la secuencia correcta.
Una versión más breve:
fuente
El método que está buscando es Series.combine. Sin embargo, parece que se debe tener cuidado con los tipos de datos. En su ejemplo, usted (como hice cuando probé la respuesta) ingenuamente llamaría
Sin embargo, esto arroja el error:
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:
fuente
La forma en que ha escrito f necesita dos entradas. Si observa el mensaje de error, dice que no está proporcionando dos entradas a f, solo una. El mensaje de error es correcto.
La falta de coincidencia se debe a que df [['' col1 ',' col2 ']] devuelve un único marco de datos con dos columnas, no dos columnas separadas.
Debe cambiar su f para que tome una sola entrada, mantenga el marco de datos anterior como entrada, luego divídalo en x, y dentro del cuerpo de la función. Luego haga lo que necesite y devuelva un valor único.
Necesita esta firma de función porque la sintaxis es .apply (f) Por lo tanto, f necesita tomar la única cosa = marco de datos y no dos cosas, que es lo que su f actual espera.
Como no ha proporcionado el cuerpo de f, no puedo ayudarlo en más detalles, pero esto debería proporcionar la salida sin cambiar fundamentalmente su código o usar algunos otros métodos en lugar de aplicar
fuente
Voy a votar por np.vectorize. Le permite disparar más de x número de columnas y no tratar con el marco de datos en la función, por lo que es ideal para funciones que no controla o hacer algo como enviar 2 columnas y una constante en una función (es decir, col_1, col_2, 'foo').
fuente
Devolver una lista de
apply
es una operación peligrosa ya que no se garantiza que el objeto resultante sea una Serie o un Marco de datos. Y se pueden plantear excepciones en ciertos casos. Veamos un ejemplo simple:Hay tres resultados posibles al devolver una lista de
apply
1) Si la longitud de la lista devuelta no es igual al número de columnas, se devuelve una serie de listas.
2) Cuando la longitud de la lista devuelta es igual al número de columnas, se devuelve un DataFrame y cada columna obtiene el valor correspondiente en la lista.
3) Si la longitud de la lista devuelta es igual al número de columnas para la primera fila pero tiene al menos una fila donde la lista tiene un número diferente de elementos que el número de columnas, se genera un ValueError.
Respondiendo el problema sin aplicar
Usar
apply
con axis = 1 es muy lento. Es posible obtener un rendimiento mucho mejor (especialmente en conjuntos de datos más grandes) con métodos iterativos básicos.Crear un marco de datos más grande
Tiempos
@Thomas respuesta
fuente
Estoy seguro de que esto no es tan rápido como las soluciones que usan operaciones Pandas o Numpy, pero si no desea reescribir su función, puede usar map. Usando los datos de ejemplo originales:
Podríamos pasar tantos argumentos como quisiéramos a la función de esta manera. La salida es lo que queríamos
fuente
apply
conaxis=1
Mi ejemplo a tus preguntas:
fuente
Si tiene un gran conjunto de datos, puede usar una forma fácil pero más rápida (tiempo de ejecución) de hacerlo usando más rápido:
fuente
Supongo que no desea cambiar la
get_sublist
función, y solo quiere usar elapply
método DataFrame para hacer el trabajo. Para obtener el resultado que desea, he escrito dos funciones de ayuda:get_sublist_list
yunlist
. Como sugiere el nombre de la función, primero obtenga la lista de sublistas, luego extraiga esa sublista de esa lista. Finalmente, necesitamos llamar a laapply
función para aplicar esas dos funciones aldf[['col_1','col_2']]
DataFrame posteriormente.Si no utiliza
[]
para encerrar laget_sublist
función, laget_sublist_list
función devolverá una lista simple, se elevaráValueError: could not broadcast input array from shape (3) into shape (2)
, como había mencionado @Ted Petrou.fuente