una seleccionar recorrer leer filtros filtrar filas fila datos con columnas cargar python pandas pass-by-reference pass-by-value

python - recorrer - seleccionar columnas de un dataframe pandas



python pandas dataframe, ¿es paso por valor o paso por referencia (6)

Aquí está el documento para soltar:

Devuelve un nuevo objeto con etiquetas en el eje solicitado eliminado.

Entonces se crea un nuevo marco de datos. El original no ha cambiado.

Pero como para todos los objetos en python, el marco de datos se pasa a la función por referencia.

Si paso un marco de datos a una función y lo modifico dentro de la función, ¿es paso por valor o paso por referencia?

Ejecuto el siguiente código

a = pd.DataFrame({''a'':[1,2], ''b'':[3,4]}) def letgo(df): df = df.drop(''b'',axis=1) letgo(a)

el valor de a no cambia después de la llamada a la función. ¿Significa que es paso por valor?

También probé lo siguiente

xx = np.array([[1,2], [3,4]]) def letgo2(x): x[1,1] = 100 def letgo3(x): x = np.array([[3,3],[3,3]])

Resulta que letgo2() cambia xx y letgo3() no. ¿Por qué es como este?


La pregunta no es PBV vs. PBR. Estos nombres solo causan confusión en un lenguaje como Python; fueron inventados para lenguajes que funcionan como C o Fortran (como los lenguajes PBV y PBR por excelencia). Es cierto, pero no esclarecedor, que Python siempre pasa por valor. La pregunta aquí es si el valor en sí está mutado o si obtiene un nuevo valor. Los pandas generalmente se equivocan del lado de este último.

http://nedbatchelder.com/text/names.html explica muy bien cuál es el sistema de nombres de Python.


La respuesta corta es que Python siempre pasa por valor, pero cada variable de Python es en realidad un puntero a algún objeto, por lo que a veces parece pasar por referencia.

En Python cada objeto es mutable o no mutable. por ejemplo, las listas, los dictos, los módulos y los marcos de datos de Pandas son mutables, y las entradas, cadenas y tuplas no son mutables. Los objetos mutables se pueden cambiar internamente (por ejemplo, agregar un elemento a una lista), pero los objetos no mutables no.

Como dije al principio, puedes pensar en cada variable de Python como un puntero a un objeto. Cuando pasa una variable a una función, la variable (puntero) dentro de la función es siempre una copia de la variable (puntero) que se pasó. Entonces, si asigna algo nuevo a la variable interna, todo lo que está haciendo es cambiar la variable local para apuntar a un objeto diferente. Esto no altera (muta) el objeto original al que apuntaba la variable, ni hace que la variable externa apunte al nuevo objeto. En este punto, la variable externa todavía apunta al objeto original, pero la variable interna apunta a un nuevo objeto.

Si desea modificar el objeto original (solo es posible con tipos de datos mutables), debe hacer algo que altere el objeto sin asignar un valor completamente nuevo a la variable local. Es por eso que letgo() y letgo3() dejan el elemento externo inalterado, pero letgo2() altera.

Como señaló @ursan, si letgo() usara algo como esto en su lugar, alteraría (mutaría) el objeto original al que apunta df , lo que cambiaría el valor visto a través de la variable global a :

def letgo(df): df.drop(''b'', axis=1, inplace=True) a = pd.DataFrame({''a'':[1,2], ''b'':[3,4]}) letgo(a) # will alter a

En algunos casos, puede vaciar completamente la variable original y rellenarla con nuevos datos, sin hacer una asignación directa, por ejemplo, esto alterará el objeto original al que v apunta, lo que cambiará los datos que se ven cuando usa v más tarde:

def letgo3(x): x[:] = np.array([[3,3],[3,3]]) v = np.empty((2, 2)) letgo3(v) # will alter v

Tenga en cuenta que no estoy asignando algo directamente a x ; Estoy asignando algo a todo el rango interno de x .

Si absolutamente debe crear un objeto completamente nuevo y hacerlo visible externamente (que a veces es el caso con los pandas), tiene dos opciones. La opción ''limpiar'' sería simplemente devolver el nuevo objeto, por ejemplo,

def letgo(df): df = df.drop(''b'',axis=1) return df a = pd.DataFrame({''a'':[1,2], ''b'':[3,4]}) a = letgo(a)

Otra opción sería llegar fuera de su función y alterar directamente una variable global. Esto cambia a para apuntar a un nuevo objeto, y cualquier función que se refiera a a posterior verá ese nuevo objeto:

def letgo(): global a a = a.drop(''b'',axis=1) a = pd.DataFrame({''a'':[1,2], ''b'':[3,4]}) letgo() # will alter a!

La modificación directa de las variables globales suele ser una mala idea, porque cualquiera que lea su código tendrá dificultades para descubrir cómo se modificó. (Generalmente uso variables globales para parámetros compartidos usados ​​por muchas funciones en un script, pero no dejo que alteren esas variables globales).


Para agregar a la respuesta de @Mike Graham, quien señaló una muy buena lectura:

En su caso, lo que es importante recordar es la diferencia entre nombres y valores . a , df , xx , x , son todos nombres , pero se refieren a los mismos o diferentes valores en diferentes puntos de sus ejemplos:

  • En el primer ejemplo, letgo vuelve a vincular df a otro valor, porque df.drop devuelve un nuevo DataFrame menos que establezca el argumento inplace = True ( consulte el documento ). Eso significa que el nombre df (local para la función letgo ), que se refería al valor de a , ahora se refiere a un nuevo valor, aquí el valor de retorno df.drop . El valor a se refiere a todavía existe y no ha cambiado.

  • En el segundo ejemplo, letgo2 muta x , sin letgo2 , razón por la cual xx es modificado por letgo2 . A diferencia del ejemplo anterior, aquí el nombre local x siempre se refiere al valor al que se refiere el nombre xx , y cambia ese valor en su lugar , razón por la cual el valor al que se refiere xx ha cambiado.

  • En el tercer ejemplo, letgo3 vuelve a vincular x a un nuevo np.array . Eso hace que el nombre x , local, sea letgo3 y que anteriormente se refiriera al valor de xx , ahora se refiera a otro valor, el nuevo np.array . El valor al que se refiere xx no ha cambiado.


Python no es pasar por valor ni pasar por referencia. Es pasar por encargo.

Referencia de soporte, las preguntas frecuentes de Python: https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference

IOW:

  1. Si pasa un valor inmutable, los cambios en él no cambian su valor en la persona que llama, porque está volviendo a vincular el nombre a un nuevo objeto.
  2. Si pasa un valor mutable, los cambios realizados en la función llamada, también cambian el valor en la persona que llama, siempre que no vuelva a vincular ese nombre a un nuevo objeto. Si reasigna la variable, creando un nuevo objeto, ese cambio y los cambios posteriores al nombre no se ven en la persona que llama.

Entonces, si pasa una lista y cambia su valor 0, ese cambio se ve tanto en el llamado como en el que llama. Pero si reasigna la lista con una nueva lista, este cambio se pierde. Pero si corta la lista y la reemplaza con una nueva lista, ese cambio se ve tanto en el llamado como en la persona que llama.

P.EJ:

def change_it(list_): # This change would be seen in the caller if we left it alone list_[0] = 28 # This change is also seen in the caller, and replaces the above # change list_[:] = [1, 2] # This change is not seen in the caller. # If this were pass by reference, this change too would be seen in # caller. list_ = [3, 4] thing = [10, 20] change_it(thing) # here, thing is [1, 2]

Si eres un fanático de C, puedes pensar en esto como pasar un puntero por valor, no un puntero a un puntero a un valor, solo un puntero a un valor.

HTH.


necesita hacer ''a'' global al comienzo de la función; de lo contrario, es una variable local y no cambia la ''a'' en el código principal.