Agregar columna con valor constante al marco de datos de pandas [duplicar]

102

Dado un DataFrame:

np.random.seed(0)
df = pd.DataFrame(np.random.randn(3, 3), columns=list('ABC'), index=[1, 2, 3])
df

          A         B         C
1  1.764052  0.400157  0.978738
2  2.240893  1.867558 -0.977278
3  0.950088 -0.151357 -0.103219

¿Cuál es la forma más sencilla de agregar una nueva columna que contenga un valor constante, por ejemplo, 0?

          A         B         C  new
1  1.764052  0.400157  0.978738    0
2  2.240893  1.867558 -0.977278    0
3  0.950088 -0.151357 -0.103219    0

Esta es mi solución, pero no sé por qué esto coloca a NaN en la columna 'nueva'.

df['new'] = pd.Series([0 for x in range(len(df.index))])

          A         B         C  new
1  1.764052  0.400157  0.978738  0.0
2  2.240893  1.867558 -0.977278  0.0
3  0.950088 -0.151357 -0.103219  NaN
yemu
fuente
9
si usa un índice, está bien. df['new'] = pd.Series([0 for x in range(len(df.index))], index=df.index).
zach
5
Además, la comprensión de una lista es completamente innecesaria aquí. just do[0] * len(df.index)
acushner
@joris, quise decir que df ['nuevo'] = 0 muestra el por qué apropiado de asignar ceros a toda la columna, pero no explica por qué mi primer intento inserta NaN. Esto fue respondido por Philip Cloud en la respuesta que acepté.
yemu
7
Simplemente hazlodf['new'] = 0
flow2k

Respuestas:

21

La razón por la que esto se coloca NaNen una columna es porque df.indexy los Indexde su objeto del lado derecho son diferentes. @zach muestra la forma correcta de asignar una nueva columna de ceros. En general, pandasintenta hacer la mayor alineación de índices posible. Una desventaja es que cuando los índices no están alineados, obtienes NaNdonde no están alineados. Experimente con los métodos reindexy alignpara obtener algo de intuición sobre los trabajos de alineación con objetos que tienen índices alineados parcial, totalmente y no alineados. Por ejemplo, así es como DataFrame.align()funciona con índices parcialmente alineados:

In [7]: from pandas import DataFrame

In [8]: from numpy.random import randint

In [9]: df = DataFrame({'a': randint(3, size=10)})

In [10]:

In [10]: df
Out[10]:
   a
0  0
1  2
2  0
3  1
4  0
5  0
6  0
7  0
8  0
9  0

In [11]: s = df.a[:5]

In [12]: dfa, sa = df.align(s, axis=0)

In [13]: dfa
Out[13]:
   a
0  0
1  2
2  0
3  1
4  0
5  0
6  0
7  0
8  0
9  0

In [14]: sa
Out[14]:
0     0
1     2
2     0
3     1
4     0
5   NaN
6   NaN
7   NaN
8   NaN
9   NaN
Name: a, dtype: float64
Phillip Cloud
fuente
10
i no downvote pero le falta el código de comentarios, hace que sea difícil de seguir, junto con que usted está tratando de lograr en el fragmento
reparación
8
Esto realmente no responde a la pregunta. OP pregunta cómo agregar una nueva columna que contenga un valor constante.
cs95
No estoy de acuerdo con que solo haya una pregunta aquí. Hay "¿Cómo asigno un valor constante a una columna?" así como "Mi intento de hacer esto no funciona de la manera X, ¿por qué se comporta de forma inesperada?" Creo que he abordado ambos puntos, el primero refiriéndome a otra respuesta. Por favor lea todo el texto de mi respuesta.
Phillip Cloud
Creo que el problema radica en la pregunta y no en su respuesta. Hay dos preguntas distintas contenidas en esta publicación y, como resultado, se requieren dos respuestas distintas para responder la pregunta. Creo que esto debería haber sido marcado como demasiado amplio y el cartel debería haber hecho dos preguntas por separado.
Kevin
83

Asignación in situ súper simple: df['new'] = 0

Para modificaciones in situ, realice una asignación directa. Esta asignación es transmitida por pandas para cada fila.

df = pd.DataFrame('x', index=range(4), columns=list('ABC'))
df

   A  B  C
0  x  x  x
1  x  x  x
2  x  x  x
3  x  x  x

df['new'] = 'y'
# Same as,
# df.loc[:, 'new'] = 'y'
df

   A  B  C new
0  x  x  x   y
1  x  x  x   y
2  x  x  x   y
3  x  x  x   y

Nota para columnas de objetos

Si desea agregar una columna de listas vacías, este es mi consejo:

  • Considere no hacer esto. objectlas columnas son malas noticias en términos de rendimiento. Reconsidere cómo se estructuran sus datos.
  • Considere almacenar sus datos en una estructura de datos dispersa. Más información: estructuras de datos dispersas
  • Si debe almacenar una columna de listas, asegúrese de no copiar la misma referencia varias veces.

    # Wrong
    df['new'] = [[]] * len(df)
    # Right
    df['new'] = [[] for _ in range(len(df))]
    

Generando una copia: df.assign(new=0)

Si necesita una copia en su lugar, use DataFrame.assign:

df.assign(new='y')

   A  B  C new
0  x  x  x   y
1  x  x  x   y
2  x  x  x   y
3  x  x  x   y

Y, si necesita asignar varias columnas con el mismo valor, esto es tan simple como,

c = ['new1', 'new2', ...]
df.assign(**dict.fromkeys(c, 'y'))

   A  B  C new1 new2
0  x  x  x    y    y
1  x  x  x    y    y
2  x  x  x    y    y
3  x  x  x    y    y

Asignación de varias columnas

Por último, si necesita asignar varias columnas con diferentes valores, puede utilizarlo assigncon un diccionario.

c = {'new1': 'w', 'new2': 'y', 'new3': 'z'}
df.assign(**c)

   A  B  C new1 new2 new3
0  x  x  x    w    y    z
1  x  x  x    w    y    z
2  x  x  x    w    y    z
3  x  x  x    w    y    z
cs95
fuente
18

Con los pandas modernos puedes hacer lo siguiente:

df['new'] = 0
Roko Mijic
fuente
1
¿Puede señalar qué respuestas específicas están desactualizadas? Dejemos un comentario debajo de ellos para que los autores tengan la oportunidad de mejorar.
cs95
1
Para su información, la única diferencia entre esta respuesta y la respuesta cs95 (AKA, yo) es el nombre y el valor de la columna. Todas las piezas están ahí.
cs95
1
No es tanto que estén desactualizados, pero esta respuesta es menos detallada que las demás y es más fácil de leer.
Joey
1
@Joey No puedo discutir con esa lógica, supongo que esta respuesta es más adecuada para las personas que solo buscan copiar y pegar cualquier cosa que funcione, en lugar de buscar comprender y aprender más sobre la biblioteca. Touche.
cs95
1
@ cs95 sí, su respuesta permite que las personas aprendan más. Además, el df ['nuevo'] = 0 resaltado en el título es bueno para la legibilidad. Yo también lo he votado. Menos detallado que df.apply (lambda x: 0, eje = 1)
Joey
7

Aquí hay otro trazador de líneas usando lambdas (cree una columna con un valor constante = 10)

df['newCol'] = df.apply(lambda x: 10, axis=1)

antes de

df
    A           B           C
1   1.764052    0.400157    0.978738
2   2.240893    1.867558    -0.977278
3   0.950088    -0.151357   -0.103219

después

df
        A           B           C           newCol
    1   1.764052    0.400157    0.978738    10
    2   2.240893    1.867558    -0.977278   10
    3   0.950088    -0.151357   -0.103219   10
Grant Shannon
fuente
5
df['newCol'] = 10también es un trazador de líneas (y es más rápido). ¿Cuál es la ventaja de usar aplicar aquí?
cs95
2
no estoy tratando de competir con usted aquí, solo mostrando un enfoque alternativo.
Grant Shannon
@ cs95 Esto es útil. Quería crear una nueva columna donde cada valor fuera una lista vacía separada. Solo este método funciona.
Yatharth Agarwal
@YatharthAgarwal Te lo daré, pero también tiene sentido dado que pandas no está diseñado para funcionar bien con columnas de listas.
cs95
1
@YatharthAgarwal Si necesita asignar listas vacías, esta sigue siendo una solución insatisfactoria porque usa aplicar. Probardf['new'] = [[] for _ in range(len(df))]
cs95