Pregunta Agregar una nueva columna al DataFrame existente en Python pandas


Tengo el siguiente DataFrame indexado con columnas con nombre y filas no continuas:

          a         b         c         d
2  0.671399  0.101208 -0.181532  0.241273
3  0.446172 -0.243316  0.051767  1.577318
5  0.614758  0.075793 -0.451460 -0.012493

Me gustaría agregar una nueva columna, 'e', a la trama de datos existente y no quiere cambiar nada en la trama de datos (es decir, la nueva columna siempre tiene la misma longitud que el DataFrame).

0   -0.335485
1   -1.166658
2   -0.385571
dtype: float64

Probé diferentes versiones de join, append, merge, pero no obtuve el resultado que quería, solo errores como máximo. ¿Cómo puedo agregar una columna? e al ejemplo anterior?


568
2017-09-23 19:00


origen


Respuestas:


Use los índices df1 originales para crear la serie:

df1['e'] = Series(np.random.randn(sLength), index=df1.index)


Editar 2015
Algunos informaron para obtener el SettingWithCopyWarning con este código
Sin embargo, el código todavía funciona perfecto con la versión actual de pandas 0.16.1.

>>> sLength = len(df1['a'])
>>> df1
          a         b         c         d
6 -0.269221 -0.026476  0.997517  1.294385
8  0.917438  0.847941  0.034235 -0.448948

>>> df1['e'] = p.Series(np.random.randn(sLength), index=df1.index)
>>> df1
          a         b         c         d         e
6 -0.269221 -0.026476  0.997517  1.294385  1.757167
8  0.917438  0.847941  0.034235 -0.448948  2.228131

>>> p.version.short_version
'0.16.1'

los SettingWithCopyWarning tiene como objetivo informar sobre una asignación posiblemente no válida en una copia del Dataframe. No necesariamente dice que lo hiciste mal (puede desencadenar falsos positivos), pero desde 0.13.0 te permite saber que hay métodos más adecuados para el mismo propósito. Entonces, si recibes la advertencia, solo sigue sus consejos: Intenta usar .loc [row_index, col_indexer] = value en su lugar

>>> df1.loc[:,'f'] = p.Series(np.random.randn(sLength), index=df1.index)
>>> df1
          a         b         c         d         e         f
6 -0.269221 -0.026476  0.997517  1.294385  1.757167 -0.050927
8  0.917438  0.847941  0.034235 -0.448948  2.228131  0.006109
>>> 

De hecho, este es actualmente el método más eficiente como descrito en pandas documentos



Editar 2017

Como se indicó en los comentarios y por @Alexander, actualmente, el mejor método para agregar los valores de una serie como una nueva columna de un DataFrame podría estar usando assign:

df1 = df1.assign(e=p.Series(np.random.randn(sLength)).values)

647
2017-09-23 19:24



Esta es la manera simple de agregar una nueva columna: df['e'] = e


142
2017-12-12 16:04



Me gustaría agregar una nueva columna, 'e', ​​al marco de datos existente y no cambiar nada en el marco de datos. (La serie siempre tiene la misma longitud que un marco de datos).

Supongo que los valores del índice en e emparejar ésos adentro df1.

La forma más fácil de iniciar una nueva columna llamada e, y asígnele los valores de su serie e:

df['e'] = e.values

asignar (Pandas 0.16.0+)

A partir de Pandas 0.16.0, también puedes usar assign, que asigna nuevas columnas a un DataFrame y devuelve un nuevo objeto (una copia) con todas las columnas originales además de las nuevas.

df1 = df1.assign(e=e.values)

Según este ejemplo (que también incluye el código fuente del assign función), también puede incluir más de una columna:

df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
>>> df.assign(mean_a=df.a.mean(), mean_b=df.b.mean())
   a  b  mean_a  mean_b
0  1  3     1.5     3.5
1  2  4     1.5     3.5

En contexto con tu ejemplo:

np.random.seed(0)
df1 = pd.DataFrame(np.random.randn(10, 4), columns=['a', 'b', 'c', 'd'])
mask = df1.applymap(lambda x: x <-0.7)
df1 = df1[-mask.any(axis=1)]
sLength = len(df1['a'])
e = pd.Series(np.random.randn(sLength))

>>> df1
          a         b         c         d
0  1.764052  0.400157  0.978738  2.240893
2 -0.103219  0.410599  0.144044  1.454274
3  0.761038  0.121675  0.443863  0.333674
7  1.532779  1.469359  0.154947  0.378163
9  1.230291  1.202380 -0.387327 -0.302303

>>> e
0   -1.048553
1   -1.420018
2   -1.706270
3    1.950775
4   -0.509652
dtype: float64

df1 = df1.assign(e=e.values)

>>> df1
          a         b         c         d         e
0  1.764052  0.400157  0.978738  2.240893 -1.048553
2 -0.103219  0.410599  0.144044  1.454274 -1.420018
3  0.761038  0.121675  0.443863  0.333674 -1.706270
7  1.532779  1.469359  0.154947  0.378163  1.950775
9  1.230291  1.202380 -0.387327 -0.302303 -0.509652

La descripción de esta nueva característica cuando se introdujo por primera vez se puede encontrar aquí.


88
2018-02-14 00:49



Haciendo esto directamente a través de NumPy será el más eficiente:

df1['e'] = np.random.randn(sLength)

Tenga en cuenta que mi sugerencia original (muy antigua) era usar map (que es mucho más lento):

df1['e'] = df1['a'].map(lambda x: np.random.random())

33
2017-09-23 19:22



Parece que en las últimas versiones de los Pandas el camino a seguir es usar df.assign:

df1 = df1.assign(e=np.random.randn(sLength))

No produce SettingWithCopyWarning.


27
2017-07-21 17:35



Tengo el temido SettingWithCopyWarningy no se corrigió utilizando la sintaxis iloc. My DataFrame fue creado por read_sql desde una fuente ODBC. Usando una sugerencia de lowtech arriba, lo siguiente funcionó para mí:

df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength),  index=df.index))

Esto funcionó bien para insertar la columna al final. No sé si es el más eficiente, pero no me gustan los mensajes de advertencia. Creo que hay una solución mejor, pero no puedo encontrarla, y creo que depende de algún aspecto del índice.
Nota. Que esto solo funciona una vez y dará un mensaje de error si intenta sobrescribir una columna existente.
Nota Como se indica arriba, y desde 0.16.0, asignar es la mejor solución. Ver documentación http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign  Funciona bien para el tipo de flujo de datos donde no sobrescribe sus valores intermedios.


14
2018-06-11 09:45



Asignación de columna súper simple

Un marco de datos de pandas se implementa como un dictado ordenado de columnas.

Esto significa que el __getitem__  [] no solo se puede usar para obtener una determinada columna, sino __setitem__  [] = se puede usar para asignar una nueva columna.

Por ejemplo, este marco de datos puede tener una columna agregada simplemente usando el [] accesor

    size      name color
0    big      rose   red
1  small    violet  blue
2  small     tulip   red
3  small  harebell  blue

df['protected'] = ['no', 'no', 'no', 'yes']

    size      name color protected
0    big      rose   red        no
1  small    violet  blue        no
2  small     tulip   red        no
3  small  harebell  blue       yes

Tenga en cuenta que esto funciona incluso si el índice del marco de datos está desactivado.

df.index = [3,2,1,0]
df['protected'] = ['no', 'no', 'no', 'yes']
    size      name color protected
3    big      rose   red        no
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue       yes

[] = es el camino a seguir, pero ten cuidado!

Sin embargo, si tienes un pd.Series y trate de asignarlo a un marco de datos donde los índices están desactivados, se encontrará con problemas. Ver ejemplo:

df['protected'] = pd.Series(['no', 'no', 'no', 'yes'])
    size      name color protected
3    big      rose   red       yes
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue        no

Esto es porque pd.Series por defecto tiene un índice enumerado de 0 a n. Y los pandas [] = método intentos  para ser inteligente"

Lo que realmente está sucediendo

Cuando usas el [] = El método pandas está realizando silenciosamente una unión externa o fusión externa utilizando el índice del marco de datos de la mano izquierda y el índice de la serie de la mano derecha. df['column'] = series

Nota al margen

Esto causa rápidamente disonancia cognitiva, ya que []= método está tratando de hacer muchas cosas diferentes dependiendo de la entrada, y el resultado no puede predecirse a menos que sólo sé cómo funcionan los pandas Por lo tanto, aconsejaría contra el []= en bases de código, pero al explorar datos en un cuaderno, está bien.

Repasando el problema

Si tienes un pd.Series y desea asignarlo de arriba a abajo, o si está codificando código productivo y no está seguro del orden de índice, vale la pena proteger este tipo de problema.

Podrías abatir el pd.Series a un np.ndarray o una list, esto hará el truco.

df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values

o

df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes']))

Pero esto no es muy explícito.

Algún codificador puede venir y decir "Oye, esto parece redundante, voy a optimizar esto".

Manera explícita

Establecer el índice de pd.Series ser el índice de la df es explícito.

df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index)

O más realista, es probable que tenga un pd.Series ya disponible.

protected_series = pd.Series(['no', 'no', 'no', 'yes'])
protected_series.index = df.index

3     no
2     no
1     no
0    yes

Ahora se puede asignar

df['protected'] = protected_series

    size      name color protected
3    big      rose   red        no
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue       yes

Manera alternativa con df.reset_index()

Dado que la disonancia del índice es el problema, si considera que el índice del marco de datos debería no dicte cosas, simplemente puede soltar el índice, esto debería ser más rápido, pero no es muy limpio, ya que su función ahora probablemente hace dos cosas

df.reset_index(drop=True)
protected_series.reset_index(drop=True)
df['protected'] = protected_series

    size      name color protected
0    big      rose   red        no
1  small    violet  blue        no
2  small     tulip   red        no
3  small  harebell  blue       yes

Nota sobre df.assign

Mientras df.assign hazlo más explícito de lo que estás haciendo, en realidad tiene todos los mismos problemas que el anterior []=

df.assign(protected=pd.Series(['no', 'no', 'no', 'yes']))
    size      name color protected
3    big      rose   red       yes
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue        no

Solo ten cuidado df.assign que su columna no se llama self. Causará errores. Esto hace df.assign  maloliente, ya que hay este tipo de artefactos en la función.

df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'

Usted puede decir: "Bueno, simplemente no usaré self entonces ". Pero quién sabe cómo cambiará esta función en el futuro para sustentar nuevos argumentos. Tal vez su nombre de columna será un argumento en una nueva actualización de pandas, causando problemas con la actualización.


14
2018-04-03 08:59



Si desea establecer toda la columna nueva en un valor base inicial (p. None), Puedes hacerlo: df1['e'] = None

Esto realmente asignaría el tipo de "objeto" a la celda. Entonces, más adelante puede colocar tipos de datos complejos, como listas, en celdas individuales.


10
2017-10-13 16:53



Infalible:

df.loc[:, 'NewCol'] = 'New_Val'

Ejemplo:

df = pd.DataFrame(data=np.random.randn(20, 4), columns=['A', 'B', 'C', 'D'])

df

           A         B         C         D
0  -0.761269  0.477348  1.170614  0.752714
1   1.217250 -0.930860 -0.769324 -0.408642
2  -0.619679 -1.227659 -0.259135  1.700294
3  -0.147354  0.778707  0.479145  2.284143
4  -0.529529  0.000571  0.913779  1.395894
5   2.592400  0.637253  1.441096 -0.631468
6   0.757178  0.240012 -0.553820  1.177202
7  -0.986128 -1.313843  0.788589 -0.707836
8   0.606985 -2.232903 -1.358107 -2.855494
9  -0.692013  0.671866  1.179466 -1.180351
10 -1.093707 -0.530600  0.182926 -1.296494
11 -0.143273 -0.503199 -1.328728  0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832  0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15  0.955298 -1.430019  1.434071 -0.088215
16 -0.227946  0.047462  0.373573 -0.111675
17  1.627912  0.043611  1.743403 -0.012714
18  0.693458  0.144327  0.329500 -0.655045
19  0.104425  0.037412  0.450598 -0.923387


df.drop([3, 5, 8, 10, 18], inplace=True)

df

           A         B         C         D
0  -0.761269  0.477348  1.170614  0.752714
1   1.217250 -0.930860 -0.769324 -0.408642
2  -0.619679 -1.227659 -0.259135  1.700294
4  -0.529529  0.000571  0.913779  1.395894
6   0.757178  0.240012 -0.553820  1.177202
7  -0.986128 -1.313843  0.788589 -0.707836
9  -0.692013  0.671866  1.179466 -1.180351
11 -0.143273 -0.503199 -1.328728  0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832  0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15  0.955298 -1.430019  1.434071 -0.088215
16 -0.227946  0.047462  0.373573 -0.111675
17  1.627912  0.043611  1.743403 -0.012714
19  0.104425  0.037412  0.450598 -0.923387

df.loc[:, 'NewCol'] = 0

df
           A         B         C         D  NewCol
0  -0.761269  0.477348  1.170614  0.752714       0
1   1.217250 -0.930860 -0.769324 -0.408642       0
2  -0.619679 -1.227659 -0.259135  1.700294       0
4  -0.529529  0.000571  0.913779  1.395894       0
6   0.757178  0.240012 -0.553820  1.177202       0
7  -0.986128 -1.313843  0.788589 -0.707836       0
9  -0.692013  0.671866  1.179466 -1.180351       0
11 -0.143273 -0.503199 -1.328728  0.610552       0
12 -0.923110 -1.365890 -1.366202 -1.185999       0
13 -2.026832  0.273593 -0.440426 -0.627423       0
14 -0.054503 -0.788866 -0.228088 -0.404783       0
15  0.955298 -1.430019  1.434071 -0.088215       0
16 -0.227946  0.047462  0.373573 -0.111675       0
17  1.627912  0.043611  1.743403 -0.012714       0
19  0.104425  0.037412  0.450598 -0.923387       0

6
2018-04-12 11:22



  1. Primero crea una lista de Python que tenga datos relevantes.
  2. Utilizar esta:     df ['e'] = list_of_e

6
2018-06-05 00:53



Permítanme agregar eso, al igual que para hum3, .loc no resolvió el SettingWithCopyWarning y tuve que recurrir a df.insert(). En mi caso, falso positivo fue generado por indexación de cadena "falsa" dict['a']['e'], dónde 'e' es la nueva columna, y dict['a'] es un DataFrame proveniente del diccionario.

También tenga en cuenta que si sabe lo que está haciendo, puede cambiar la advertencia utilizando pd.options.mode.chained_assignment = None y que use una de las otras soluciones dadas aquí.


5
2017-10-22 14:21