Bagaimana cara menambahkan beberapa kolom ke bingkai data panda dalam satu tugas?


122

Saya baru mengenal panda dan mencoba mencari cara untuk menambahkan beberapa kolom ke panda secara bersamaan. Setiap bantuan di sini dihargai. Idealnya saya ingin melakukan ini dalam satu langkah daripada beberapa langkah berulang ...

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...

Anda perlu menyatakan kesalahan apa yang Anda dapatkan. Ketika saya mencoba ini di pandas 1.0 saya mendapatkanKeyError: "None of [Index(['column_new_1', 'column_new_2', 'column_new_3'], dtype='object')] are in the [columns]"
smci

Jawaban:


185

Saya berharap sintaks Anda berfungsi juga. Masalah muncul karena saat Anda membuat kolom baru dengan sintaks daftar kolom ( df[[new1, new2]] = ...), panda mengharuskan sisi kanan menjadi DataFrame (perhatikan bahwa tidak masalah jika kolom dari DataFrame memiliki nama yang sama dengan kolom Anda sedang membuat).

Sintaks Anda berfungsi dengan baik untuk menetapkan nilai skalar ke kolom yang ada , dan panda juga dengan senang hati menetapkan nilai skalar ke kolom baru menggunakan sintaks kolom tunggal ( df[new1] = ...). Jadi solusinya adalah dengan mengubahnya menjadi beberapa tugas kolom tunggal, atau membuat DataFrame yang sesuai untuk sisi kanan.

Berikut beberapa pendekatan yang akan berhasil:

import pandas as pd
import numpy as np

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

Lalu salah satu dari berikut ini:

1) Tiga tugas dalam satu, menggunakan pembongkaran daftar:

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

2) dengan DataFramemudah memperluas satu baris agar sesuai dengan indeks, sehingga Anda dapat melakukan ini:

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

3) Buat bingkai data sementara dengan kolom baru, kemudian gabungkan dengan bingkai data asli nanti:

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) Mirip dengan yang sebelumnya, tetapi menggunakan joinalih-alih concat(mungkin kurang efisien):

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

5) Menggunakan dict adalah cara yang lebih "alami" untuk membuat bingkai data baru daripada dua sebelumnya, tetapi kolom baru akan diurutkan menurut abjad (setidaknya sebelum Python 3.6 atau 3.7 ):

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

6) Gunakan .assign()dengan beberapa argumen kolom.

Saya sangat menyukai varian ini pada jawaban @ zero, tetapi seperti yang sebelumnya, kolom baru akan selalu diurutkan menurut abjad, setidaknya dengan versi awal Python:

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

7) Ini menarik (berdasarkan https://stackoverflow.com/a/44951376/3830997 ), tetapi saya tidak tahu kapan itu sepadan dengan masalahnya:

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) Pada akhirnya, sulit untuk mengalahkan tiga tugas terpisah:

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

Catatan: banyak dari opsi ini telah tercakup dalam jawaban lain: Tambahkan beberapa kolom ke DataFrame dan atur sama dengan kolom yang ada , Apakah mungkin menambahkan beberapa kolom sekaligus ke DataFrame pandas? , Tambahkan beberapa kolom kosong ke pandas DataFrame


Tidakkah pendekatan # 7 ( .reindex) akan mengubah indeks bingkai data? Mengapa seseorang ingin mengubah indeks yang tidak perlu saat menambahkan kolom kecuali itu adalah tujuan eksplisit ...
Acumenus

1
.reindex()digunakan dengan columnsargumen, jadi hanya mengubah kolom "indeks" (nama). Itu tidak mengubah indeks baris.
Matthias Fripp

untuk beberapa pendekatan, Anda dapat menggunakan OrderedDict: misalnya,df.join(pd.DataFrame( OrderedDict([('column_new_2', 'dogs'),('column_new_1', np.nan),('column_new_3', 3)]), index=df.index ))
hashmuke

@hashmuke Itu masuk akal untuk versi awal Python. Ini mungkin menarik terutama bagi orang-orang yang menggunakan kamus untuk banyak hal di Pandas, misalnya, 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
Jika Anda menggunakan opsi dengan join, pastikan Anda tidak memiliki duplikat di indeks Anda (atau gunakan yang reset_indexpertama). Mungkin menghemat beberapa jam debugging.
Guido

40

Anda bisa menggunakan assigndikt nama dan nilai kolom.

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

Apakah ada cara untuk melakukan hal yang sama yang mempertahankan urutan kolom tertentu?
pengguna48956

1
Anda dapat mempertahankan pengurutan tertentu dengan versi Python sebelumnya dengan memanggil assign beberapa kali: df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
skasch

Jika nama kolom hanya mengandung string yang nama variabel hukum: df.assign(col_new_1=np.nan, col2_new_2='dogs', col3_new_3=3). Ini menjaga ketertiban.
Tobias Bergkvist

9

Dengan penggunaan 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

Tidak terlalu yakin dengan apa yang ingin Anda lakukan [np.nan, 'dogs',3]. Mungkin sekarang mengaturnya sebagai nilai default?

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

jika ada cara untuk melakukan bagian ke-2 Anda dalam satu langkah - ya nilai konstan di kolom sebagai contoh.
runningbirds

3

penggunaan pemahaman daftar, pd.DataFramedanpd.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)

masukkan deskripsi gambar di sini


3

jika menambahkan banyak kolom yang hilang (a, b, c, ....) dengan nilai yang sama, di sini 0, saya melakukan ini:

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

Ini didasarkan pada varian kedua dari jawaban yang diterima.


0

Hanya ingin menunjukkan opsi2 itu dalam jawaban @Matthias Fripp

(2) Saya tidak selalu mengharapkan DataFrame bekerja dengan cara ini, tetapi memang demikian

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

sudah didokumentasikan dalam dokumentasi pandas sendiri http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

Anda dapat memberikan daftar kolom ke [] untuk memilih kolom dalam urutan itu. Jika kolom tidak terdapat dalam DataFrame, pengecualian akan dimunculkan. Beberapa kolom juga dapat diatur dengan cara ini. Anda mungkin menemukan ini berguna untuk menerapkan transformasi ( di tempat ) ke subset kolom.


Saya pikir ini cukup standar untuk tugas multi-kolom. Bagian yang mengejutkan saya adalah pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)mereplikasi satu baris yang diberikan untuk membuat keseluruhan kerangka data dengan panjang yang sama dengan indeks.
Matthias Fripp

0

Jika Anda hanya ingin menambahkan kolom baru yang kosong, indeks ulang akan melakukan pekerjaan itu

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

contoh kode lengkap

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

jika tidak, carilah jawaban nol dengan assign


0

Saya tidak nyaman menggunakan "Indeks" dan seterusnya ... bisa muncul seperti di bawah ini

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')
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.