Como adicionar várias colunas ao dataframe do pandas em uma atribuição?

122

Eu sou novo em pandas e estou tentando descobrir como adicionar várias colunas a pandas simultaneamente. Qualquer ajuda aqui é apreciada. Idealmente, gostaria de fazer isso em uma etapa, em vez de várias etapas repetidas ...

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...
pássaros correndo
fonte
Você precisa declarar qual erro obteve. Quando tento fazer isso no pandas 1.0, receboKeyError: "None of [Index(['column_new_1', 'column_new_2', 'column_new_3'], dtype='object')] are in the [columns]"
smci

Respostas:

185

Eu esperava que sua sintaxe funcionasse também. O problema surge porque quando você cria novas colunas com a sintaxe da lista de colunas ( df[[new1, new2]] = ...), o pandas requer que o lado direito seja um DataFrame (note que na verdade não importa se as colunas do DataFrame têm os mesmos nomes que as colunas você está criando).

Sua sintaxe funciona bem para atribuir valores escalares a colunas existentes , e o pandas também fica feliz em atribuir valores escalares a uma nova coluna usando a sintaxe de coluna única ( df[new1] = ...). Portanto, a solução é converter isso em várias atribuições de coluna única ou criar um DataFrame adequado para o lado direito.

Aqui estão algumas abordagens que irá trabalhar:

import pandas as pd
import numpy as np

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

Em seguida, um dos seguintes:

1) Três atribuições em uma, usando a descompactação de lista:

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

2) DataFrameexpande convenientemente uma única linha para corresponder ao índice, para que você possa fazer o seguinte:

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

3) Faça um quadro de dados temporário com novas colunas, depois combine com o quadro de dados original:

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) Semelhante ao anterior, mas usando em joinvez de concat(pode ser menos eficiente):

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

5) Usar um dict é uma maneira mais "natural" de criar o novo quadro de dados do que os dois anteriores, mas as novas colunas serão classificadas em ordem alfabética (pelo menos antes do Python 3.6 ou 3.7 ):

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

6) Use .assign()com vários argumentos de coluna.

Gosto muito dessa variante da resposta de @zero, mas, como a anterior, as novas colunas sempre serão classificadas em ordem alfabética, pelo menos com as primeiras versões do Python:

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

7) Isso é interessante (com base em https://stackoverflow.com/a/44951376/3830997 ), mas não sei quando valeria a 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) No final, é difícil vencer três atribuições separadas:

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

Nota: muitas dessas opções já foram abordadas em outras respostas: Adicionar várias colunas ao DataFrame e defini-las iguais a uma coluna existente . É possível adicionar várias colunas de uma vez a um DataFrame do pandas? , Adicionar várias colunas vazias ao DataFrame do pandas

Matthias Fripp
fonte
A abordagem # 7 ( .reindex) não alteraria o índice do dataframe? Por que alguém iria querer alterar desnecessariamente o índice ao adicionar colunas, a menos que seja uma meta explícita ...
Acumenus
1
.reindex()é usado com o columnsargumento, portanto, ele apenas altera a coluna "índice" (nomes). Não altera o índice da linha.
Matthias Fripp
para algumas das abordagens, você pode usar OrderedDict: por exemplo,df.join(pd.DataFrame( OrderedDict([('column_new_2', 'dogs'),('column_new_1', np.nan),('column_new_3', 3)]), index=df.index ))
hashmuke
@hashmuke Isso faz sentido para as primeiras versões do Python. Pode apelar especialmente para pessoas que usam dicionários para várias coisas em Pandas, por exemplo, 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
Caso você esteja usando a opção com join, certifique-se de não ter duplicatas em seu índice (ou use um reset_indexprimeiro). Pode poupar algumas horas na depuração.
Guido
40

Você pode usar assigncom um dicionário de nomes e valores de coluna.

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
Zero
fonte
Existe uma maneira de fazer o mesmo que mantém uma ordem específica das colunas?
user48956
1
Você pode manter uma ordem específica com versões anteriores do Python chamando assign várias vezes: df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
skasch
9

Com o uso de 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

Não tenho muita certeza do que você queria fazer [np.nan, 'dogs',3]. Talvez agora os defina como valores padrão?

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
Nehal J Wani
fonte
se houvesse uma maneira de fazer sua 2ª parte em uma única etapa - sim, valores constantes nas colunas como um exemplo.
runningbirds de
3

uso de compreensão de lista, 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)

insira a descrição da imagem aqui

piRSquared
fonte
3

se adicionar muitas colunas ausentes (a, b, c, ....) com o mesmo valor, aqui 0, fiz o seguinte:

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

É baseado na segunda variante da resposta aceita.

A. Rabus
fonte
0

Só quero apontar essa opção2 na resposta de @Matthias Fripp

(2) Eu não esperaria necessariamente que o DataFrame funcionasse dessa maneira, mas funciona

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

já está documentado na própria documentação do pandas http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

Você pode passar uma lista de colunas para [] para selecionar as colunas nessa ordem. Se uma coluna não estiver contida no DataFrame, uma exceção será levantada. Várias colunas também podem ser definidas dessa maneira. Você pode achar isso útil para aplicar uma transformação ( no local ) a um subconjunto de colunas.

meia-lua
fonte
Eu acho que isso é bastante normal para atribuição de várias colunas. A parte que me surpreendeu foi que pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)replica a única linha fornecida para criar um dataframe inteiro com o mesmo comprimento do índice.
Matthias Fripp
0

Se você quiser apenas adicionar novas colunas vazias, o reindex fará o trabalho

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

exemplo de código 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')

caso contrário vá para zeros responder com atribuir

Markus Dutschke
fonte
0

Não me sinto confortável usando "Índice" e assim por diante ... poderia aparecer como abaixo

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')
Alex
fonte