Inserción de la lista en una celda: ¿por qué la locación REALMENTE funciona aquí?

Somos conscientes de que el método estándar de configuración de una sola celda está utilizando at o iat . Sin embargo, noté un comportamiento interesante que me preguntaba si alguien podría racionalizar.

Al resolver esta pregunta , me encuentro con un comportamiento extraño de loc .

 # Setup. pd.__version__ # '0.24.0rc1' df = pd.DataFrame({'A': [12, 23], 'B': [['a', 'b'], ['c', 'd']]}) df AB 0 12 [a, b] 1 23 [c, d] 

Para configurar la celda (1, ‘B’), basta con hacer esto con at, como df.at[1, 'B'] = ... Pero con loc, inicialmente intenté esto, que no funcionó:

 df.loc[1, 'B'] = ['m', 'n', 'o', 'p'] # ValueError: Must have equal len keys and value when setting with an iterable 

Así que, lo intenté (que también falló)

 df.loc[1, 'B'] = [['m', 'n', 'o', 'p']] # ValueError: Must have equal len keys and value when setting with an ndarray 

Pensé que loc también podría de alguna manera tomar listas anidadas aquí. En un extraño giro de eventos, este código funcionó:

 df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p']] df AB 0 12 [a, b] 1 23 [m, n, o, p] 

¿Por qué la loc funciona de esta manera? Además, si agrega otro elemento a cualquiera de las listas, se mostrará:

 df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p', 'q']] # ValueError: Must have equal len keys and value when setting with an iterable 

Las listas vacías tampoco funcionan. Parece inútil tener que anidar cada elemento en su propia lista.

¿Por qué loc hace esto? ¿Es este comportamiento documentado, o un error?

Related of "Inserción de la lista en una celda: ¿por qué la locación REALMENTE funciona aquí?"

Esto ocurre porque loc hace un montón de comprobación para todas las muchas casos de uso que admite. (Nota: la historia fue que loc e iloc se crearon para eliminar la ambigüedad de ix , en 2013 v0.11, pero aún hoy en día hay mucha ambigüedad en loc ).

En este caso, df.loc[1, 'B'] puede devolver:

  • un solo elemento (como en este caso, cuando hay un índice / columna único para 1 / ‘B’).
  • una Serie (si CUALQUIERA de 1 / ‘B’ aparece en el índice / columnas varias veces).
  • a DataFrame (si BOTH 1 / ‘B’ aparece en el índice / columnas varias veces).

Aparte: iloc sufre el mismo problema en este caso, aunque siempre será el primer caso, pero eso puede deberse a que loc e iloc comparten este código de asignación.

¡Así que los pandas necesitan apoyar todos esos casos para la asignación!

Una parte temprana de la lógica de asignación convierte la lista (de listas) en una matriz numpy:

 In [11]: np.array(['m', 'n', 'o', 'p']).shape Out[11]: (4,) In [12]: np.array([['m', 'n', 'o', 'p']]).shape Out[12]: (1, 4) 

Por lo tanto, no puede pasar la lista de listas y esperar obtener la matriz correcta. En su lugar, podría establecer explícitamente en una matriz de objetos:

 In [13]: a = np.empty(1, dtype=object) In [14]: a[0] = ['m', 'n', 'o', 'p'] In [15]: a Out[15]: array([list(['m', 'n', 'o', 'p'])], dtype=object) 

Ahora puedes usar esto en la tarea:

 In [16]: df.loc[0, 'B'] = a In [17]: df Out[17]: AB 0 12 [m, n, o, p] 1 23 [c, d] 

Todavía no es lo ideal, pero para reiterar que hay tantos casos de borde en loc e iloc , la solución es ser lo más explícita posible para evitarlos (utilícelos aquí). Y, de manera más general, como ya sabe, ¡evite utilizar listas dentro de un DataFrame!