Come aggiungere più colonne al dataframe di panda in un'unica assegnazione?


122

Sono nuovo per i panda e sto cercando di capire come aggiungere più colonne ai panda contemporaneamente. Qualsiasi aiuto qui è apprezzato. Idealmente, vorrei farlo in un unico passaggio piuttosto che più passaggi ripetuti ...

import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)

df[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs',3]  #thought this would work here...

Devi indicare quale errore hai ricevuto. Quando provo questo su KeyError: "None of [Index(['column_new_1', 'column_new_2', 'column_new_3'], dtype='object')] are in the [columns]"
Panda

Risposte:


185

Mi sarei aspettato che anche la tua sintassi funzionasse. Il problema sorge perché quando crei nuove colonne con la sintassi dell'elenco di colonne ( df[[new1, new2]] = ...), panda richiede che il lato destro sia un DataFrame (nota che in realtà non importa se le colonne del DataFrame hanno gli stessi nomi delle colonne stai creando).

La tua sintassi funziona bene per assegnare valori scalari a colonne esistenti e panda è anche felice di assegnare valori scalari a una nuova colonna usando la sintassi a colonna singola ( df[new1] = ...). Quindi la soluzione è convertire questo in diverse assegnazioni a colonna singola o creare un DataFrame adatto per il lato destro.

Qui ci sono diversi approcci che sarà lavorare:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'col_1': [0, 1, 2, 3],
    'col_2': [4, 5, 6, 7]
})

Quindi uno dei seguenti:

1) Tre incarichi in uno, utilizzando lo spacchettamento dell'elenco:

df['column_new_1'], df['column_new_2'], df['column_new_3'] = [np.nan, 'dogs', 3]

2) DataFrameespande comodamente una singola riga in modo che corrisponda all'indice, quindi puoi farlo:

df[['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)

3) Crea un data frame temporaneo con nuove colonne, quindi combinalo con il data frame originale in un secondo momento:

df = pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3]], 
            index=df.index, 
            columns=['column_new_1', 'column_new_2', 'column_new_3']
        )
    ], axis=1
)

4) Simile al precedente, ma usando joininvece di concat(potrebbe essere meno efficiente):

df = df.join(pd.DataFrame(
    [[np.nan, 'dogs', 3]], 
    index=df.index, 
    columns=['column_new_1', 'column_new_2', 'column_new_3']
))

5) Usare un dict è un modo più "naturale" per creare il nuovo data frame rispetto ai due precedenti, ma le nuove colonne saranno ordinate alfabeticamente (almeno prima di Python 3.6 o 3.7 ):

df = df.join(pd.DataFrame(
    {
        'column_new_1': np.nan,
        'column_new_2': 'dogs',
        'column_new_3': 3
    }, index=df.index
))

6) Utilizzare .assign()con più argomenti di colonna.

Mi piace molto questa variante alla risposta di @ zero, ma come la precedente, le nuove colonne saranno sempre ordinate alfabeticamente, almeno con le prime versioni di Python:

df = df.assign(column_new_1=np.nan, column_new_2='dogs', column_new_3=3)

7) Questo è interessante (basato su https://stackoverflow.com/a/44951376/3830997 ), ma non so quando ne varrebbe la pena:

new_cols = ['column_new_1', 'column_new_2', 'column_new_3']
new_vals = [np.nan, 'dogs', 3]
df = df.reindex(columns=df.columns.tolist() + new_cols)   # add empty cols
df[new_cols] = new_vals  # multi-column assignment works for existing cols

8) Alla fine è difficile battere tre incarichi separati:

df['column_new_1'] = np.nan
df['column_new_2'] = 'dogs'
df['column_new_3'] = 3

Nota: molte di queste opzioni sono già state trattate in altre risposte: Aggiungi più colonne a DataFrame e impostale uguali a una colonna esistente , è possibile aggiungere più colonne contemporaneamente a un DataFrame panda? , Aggiungi più colonne vuote a panda DataFrame


L'approccio # 7 ( .reindex) non altererebbe l'indice del dataframe? Perché qualcuno dovrebbe voler modificare inutilmente l'indice quando si aggiungono colonne a meno che non sia un obiettivo esplicito ...
Acumenus

1
.reindex()viene utilizzato con l' columnsargomento, quindi cambia solo la colonna "index" (nomi). Non altera l'indice di riga.
Matthias Fripp,

per alcuni approcci, puoi usare OrderedDict: per esempio,df.join(pd.DataFrame( OrderedDict([('column_new_2', 'dogs'),('column_new_1', np.nan),('column_new_3', 3)]), index=df.index ))
hashmuke

@hashmuke Questo ha senso per le prime versioni di Python. Può piacere soprattutto alle persone che usano dizionari per più cose in Panda, ad esempio, df = pd.DataFrame({'before': [1, 2, 3], 'after': [4, 5, 6]})vs.df = pd.DataFrame(OrderedDict([('before', [1, 2, 3]), ('after', [4, 5, 6])])
Matthias Fripp

2
Nel caso in cui utilizzi l'opzione con join, assicurati di non avere duplicati nel tuo indice (o usa un reset_indexprimo). Potrebbe farti risparmiare qualche ora di debug.
Guido

40

Potresti usare assigncon un dettato dei nomi e dei valori delle colonne.

In [1069]: df.assign(**{'col_new_1': np.nan, 'col2_new_2': 'dogs', 'col3_new_3': 3})
Out[1069]:
   col_1  col_2 col2_new_2  col3_new_3  col_new_1
0      0      4       dogs           3        NaN
1      1      5       dogs           3        NaN
2      2      6       dogs           3        NaN
3      3      7       dogs           3        NaN

C'è un modo per fare lo stesso che mantenga un ordinamento specifico delle colonne?
user48956

1
È possibile mantenere un ordine specifico con le versioni precedenti di Python chiamando più volte assign: df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
skasch

Se i nomi di colonna contengono solo le stringhe che sono i nomi delle variabili di legge: df.assign(col_new_1=np.nan, col2_new_2='dogs', col3_new_3=3). Questo mantiene l'ordine.
Tobias Bergkvist

9

Con l'uso di concat :

In [128]: df
Out[128]: 
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

In [129]: pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
Out[129]: 
   col_1  col_2 column_new_1 column_new_2 column_new_3
0    0.0    4.0          NaN          NaN          NaN
1    1.0    5.0          NaN          NaN          NaN
2    2.0    6.0          NaN          NaN          NaN
3    3.0    7.0          NaN          NaN          NaN

Non sono molto sicuro di cosa volevi fare [np.nan, 'dogs',3]. Forse ora impostarli come valori predefiniti?

In [142]: df1 = pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
In [143]: df1[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs', 3]

In [144]: df1
Out[144]: 
   col_1  col_2  column_new_1 column_new_2  column_new_3
0    0.0    4.0           NaN         dogs             3
1    1.0    5.0           NaN         dogs             3
2    2.0    6.0           NaN         dogs             3
3    3.0    7.0           NaN         dogs             3

se ci fosse un modo per eseguire la seconda parte in un unico passaggio - sì, valori costanti nelle colonne come esempio.
runningbirds

3

uso della comprensione delle liste pd.DataFrameepd.concat

pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3] for _ in range(df.shape[0])],
            df.index, ['column_new_1', 'column_new_2','column_new_3']
        )
    ], axis=1)

inserisci qui la descrizione dell'immagine


3

se aggiungo molte colonne mancanti (a, b, c, ....) con lo stesso valore, qui 0, ho fatto questo:

    new_cols = ["a", "b", "c" ] 
    df[new_cols] = pd.DataFrame([[0] * len(new_cols)], index=df.index)

Si basa sulla seconda variante della risposta accettata.


0

Voglio solo sottolineare quell'opzione2 nella risposta di @Matthias Fripp

(2) Non mi aspetto necessariamente che DataFrame funzioni in questo modo, ma funziona

df [['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame ([[np.nan, 'dogs', 3]], index = df.index)

è già documentato nella documentazione dei panda http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

Puoi passare un elenco di colonne a [] per selezionare le colonne in quell'ordine. Se una colonna non è contenuta nel DataFrame, verrà sollevata un'eccezione. Anche più colonne possono essere impostate in questo modo. Potrebbe essere utile per applicare una trasformazione ( sul posto ) a un sottoinsieme di colonne.


Penso che questo sia abbastanza standard per l'assegnazione a più colonne. La parte che mi ha sorpreso è stata che pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)replica l'unica riga assegnata per creare un intero dataframe della stessa lunghezza dell'indice.
Matthias Fripp

0

Se vuoi solo aggiungere nuove colonne vuote, la reindicizzazione farà il lavoro

df
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)
   col_1  col_2  column_new_1  column_new_2  column_new_3
0      0      4           NaN           NaN           NaN
1      1      5           NaN           NaN           NaN
2      2      6           NaN           NaN           NaN
3      3      7           NaN           NaN           NaN

esempio di codice completo

import numpy as np
import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)
print('df',df, sep='\n')
print()
df=df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)
print('''df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)''',df, sep='\n')

altrimenti vai per zeri rispondi con assegna


0

Non mi sento a mio agio usando "Indice" e così via ... potrebbe apparire come di seguito

df.columns
Index(['A123', 'B123'], dtype='object')

df=pd.concat([df,pd.DataFrame(columns=list('CDE'))])

df.rename(columns={
    'C':'C123',
    'D':'D123',
    'E':'E123'
},inplace=True)


df.columns
Index(['A123', 'B123', 'C123', 'D123', 'E123'], dtype='object')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.