Membuat DataFrame Pandas kosong, lalu mengisinya?

463

Saya mulai dari dokumen DataFrame panda di sini: http://pandas.pydata.org/pandas-docs/stable/dsintro.html

Saya ingin secara iteratif mengisi DataFrame dengan nilai-nilai dalam jenis perhitungan time series. Jadi pada dasarnya, saya ingin menginisialisasi DataFrame dengan kolom A, B dan baris timestamp, semua 0 atau semua NaN.

Saya kemudian akan menambahkan nilai awal dan memeriksa data ini menghitung baris baru dari baris sebelumnya, katakan row[A][t] = row[A][t-1]+1atau lebih.

Saya saat ini menggunakan kode seperti di bawah ini, tetapi saya merasa itu agak jelek dan harus ada cara untuk melakukan ini dengan DataFrame secara langsung, atau hanya cara yang lebih baik secara umum. Catatan: Saya menggunakan Python 2.7.

import datetime as dt
import pandas as pd
import scipy as s

if __name__ == '__main__':
    base = dt.datetime.today().date()
    dates = [ base - dt.timedelta(days=x) for x in range(0,10) ]
    dates.sort()

    valdict = {}
    symbols = ['A','B', 'C']
    for symb in symbols:
        valdict[symb] = pd.Series( s.zeros( len(dates)), dates )

    for thedate in dates:
        if thedate > dates[0]:
            for symb in valdict:
                valdict[symb][thedate] = 1+valdict[symb][thedate - dt.timedelta(days=1)]

    print valdict
Matthias Kauer
sumber
6
Jangan pernah menumbuhkan DataFrame! Itu selalu lebih murah untuk menambahkan ke daftar python dan kemudian mengubahnya menjadi DataFrame pada akhirnya, baik dari segi memori dan kinerja.
cs95
@ cs95 Apa perbedaan fungsi antara .appendpd dan menambahkan daftar? Saya tahu .appenddalam panda menyalin seluruh dataset ke objek baru ยด, apakah ular sanca bekerja berbeda?
Lamma
@Lamma, silakan temukan detail di jawaban saya di bawah ini. Saat menambahkan ke df, DataFrame baru dibuat setiap kali dalam memori alih-alih menggunakan yang sudah ada, yang sebenarnya merupakan pemborosan.
cs95

Jawaban:

330

Berikut beberapa saran:

Gunakan date_rangeuntuk indeks:

import datetime
import pandas as pd
import numpy as np

todays_date = datetime.datetime.now().date()
index = pd.date_range(todays_date-datetime.timedelta(10), periods=10, freq='D')

columns = ['A','B', 'C']

Catatan: kita bisa membuat DataFrame kosong (dengan NaNs) hanya dengan menulis:

df_ = pd.DataFrame(index=index, columns=columns)
df_ = df_.fillna(0) # with 0s rather than NaNs

Untuk melakukan jenis perhitungan ini untuk data, gunakan array numpy:

data = np.array([np.arange(10)]*3).T

Maka kita dapat membuat DataFrame:

In [10]: df = pd.DataFrame(data, index=index, columns=columns)

In [11]: df
Out[11]: 
            A  B  C
2012-11-29  0  0  0
2012-11-30  1  1  1
2012-12-01  2  2  2
2012-12-02  3  3  3
2012-12-03  4  4  4
2012-12-04  5  5  5
2012-12-05  6  6  6
2012-12-06  7  7  7
2012-12-07  8  8  8
2012-12-08  9  9  9
Andy Hayden
sumber
2
pd.date_range () tidak berfungsi untuk saya. Saya mencoba dengan DateRange (dari pelengkapan otomatis eclipse), tetapi itu berfungsi dengan string sebagai format tanggal, bukan? Pendekatan keseluruhan bekerja meskipun (saya mengubah indeks ke yang lain).
Matthias Kauer
2
date_range adalah fungsi pabrik untuk membuat indeks datetime dan merupakan fitur baru di 0.8.0 , saya pasti akan merekomendasikan untuk meningkatkan ke rilis stabil terbaru (0.9.1) ada banyak perbaikan bug dan fitur baru. :)
Andy Hayden
26
Dalam pengalaman saya, membuat bingkai data dengan ukuran yang diperlukan diisi dengan NaN, dan kemudian mengisi dengan nilai jauh lebih lambat daripada membuat bingkai data dengan dimensi indexx 0( columns = []), dan melampirkan satu kolom di setiap putaran loop. Maksud saya df[col_name] = pandas.Series([...])dalam satu lingkaran iterasi melalui nama kolom. Dalam kasus sebelumnya, tidak hanya alokasi memori yang membutuhkan waktu, tetapi mengganti NaNs dengan nilai-nilai baru tampaknya sangat lambat.
deeenes
5
@deeenes pasti. jawaban ini mungkin harus membuatnya lebih jelas - Anda sangat jarang (jika pernah) ingin membuat Dataframe kosong (dari NaNs).
Andy Hayden
1
Sesuai jawaban ini stackoverflow.com/a/30267881/2302569 Anda perlu menetapkan hasil dari fillna, atau lulus param inplace = Benar
JayJay
169

Jika Anda hanya ingin membuat frame data kosong dan mengisinya dengan beberapa frame data yang masuk nanti, coba ini:

newDF = pd.DataFrame() #creates a new dataframe that's empty
newDF = newDF.append(oldDF, ignore_index = True) # ignoring index is optional
# try printing some data from newDF
print newDF.head() #again optional 

Dalam contoh ini saya menggunakan panda doc ini untuk membuat bingkai data baru dan kemudian menggunakan append untuk menulis ke newDF dengan data dari oldDF.

Jika saya harus terus menambahkan data baru ke dalam newDF ini dari lebih dari satu oldDFs, saya hanya menggunakan for for loop untuk beralih ke panda. DataFrame.append ()

geekidharsh
sumber
14
Harap dicatat bahwa append(dan juga concat) menyalin dataset lengkap ke objek baru setiap kali, karenanya, iterasi dan menambahkan dapat dan akan menyebabkan hit kinerja utama. untuk info lebih lanjut lihat: pandas.pydata.org/pandas-docs/stable/merging.html
MoustafaAAtta
4
@MoustafaAAtta Apa alternatif untuk menambahkan data iteratif ke kerangka data?
MysteryGuy
2
@MoustafaAAtta Apakah Fred menjawab dalam posting ini: stackoverflow.com/questions/10715965/โ€ฆ lebih baik dalam sudut pandang ini?
MysteryGuy
@MoustafaAAtta Anda mungkin bisa menambahkan hanya baris ke bingkai data, itu masih akan membuat objek baru tetapi untuk kumpulan data yang lebih kecil, mungkin berguna. pandas.pydata.org/pandas-docs/stable/user_guide/โ€ฆ
geekidharsh
136

The Right Way โ„ข untuk Membuat DataFrame

TLDR; (cukup baca teks tebal)

Sebagian besar jawaban di sini akan memberi tahu Anda cara membuat DataFrame kosong dan mengisinya, tetapi tidak ada yang akan memberi tahu Anda bahwa itu adalah hal yang buruk untuk dilakukan.

Ini saran saya: Tunggu sampai Anda yakin Anda memiliki semua data yang perlu Anda kerjakan. Gunakan daftar untuk mengumpulkan data Anda, lalu inisialisasi DataFrame saat Anda siap.

data = []
for a, b, c in some_function_that_yields_data():
    data.append([a, b, c])

df = pd.DataFrame(data, columns=['A', 'B', 'C'])

Hal ini selalu lebih murah untuk menambahkan ke daftar dan membuat DataFrame di satu pergi daripada untuk membuat DataFrame kosong (atau salah satu dari NaN) dan append untuk itu lagi dan lagi. Daftar juga membutuhkan lebih sedikit memori dan struktur data yang jauh lebih ringan untuk digunakan , ditambahkan, dan dihapus (jika perlu).

Keuntungan lain dari metode ini dtypesdisimpulkan secara otomatis (daripada menugaskan objectmereka semua).

Keuntungan terakhir adalah bahwa a RangeIndexsecara otomatis dibuat untuk data Anda , jadi itu adalah satu hal yang kurang perlu dikhawatirkan (lihat pada orang miskin appenddan locmetode di bawah ini, Anda akan melihat elemen di keduanya yang memerlukan penanganan indeks dengan tepat).


Hal-hal yang TIDAK BISA Anda lakukan

appendatau concatdi dalam lingkaran

Inilah kesalahan terbesar yang pernah saya lihat dari pemula:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
    # or similarly,
    # df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)

Memori dialokasikan kembali untuk setiap appendatau concatoperasi yang Anda miliki. Pasangkan ini dengan satu lingkaran dan Anda memiliki operasi kompleksitas kuadratik . Dari df.appendhalaman dokumen :

Menambahkan baris ke DataFrame secara berurutan dapat lebih intensif secara komputasi daripada satu gabungan tunggal. Solusi yang lebih baik adalah menambahkan baris-baris itu ke daftar dan kemudian menggabungkan daftar dengan DataFrame asli sekaligus.

Kesalahan lain yang terkait df.appendadalah bahwa pengguna cenderung lupa menambahkan bukan fungsi di tempat , sehingga hasilnya harus ditugaskan kembali. Anda juga harus khawatir tentang dtypes:

df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)

df.dtypes
A     object   # yuck!
B    float64
C     object
dtype: object

Berurusan dengan kolom objek tidak pernah merupakan hal yang baik, karena panda tidak dapat membuat vektor operasi pada kolom tersebut. Anda harus melakukan ini untuk memperbaikinya:

df.infer_objects().dtypes
A      int64
B    float64
C     object
dtype: object

loc di dalam lingkaran

Saya juga telah melihat locdigunakan untuk menambahkan ke DataFrame yang dibuat kosong:

df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
    df.loc[len(df)] = [a, b, c]

Seperti sebelumnya, Anda belum mengalokasikan jumlah memori yang Anda butuhkan setiap kali, sehingga memori ditanam kembali setiap kali Anda membuat baris baru . Ini sama buruknya denganappend , dan bahkan lebih jelek.

Kosongkan DataFrame dari NaNs

Dan kemudian, ada membuat DataFrame NaNs, dan semua peringatan yang terkait dengannya.

df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
     A    B    C
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN
4  NaN  NaN  NaN

Itu membuat DataFrame dari kolom objek, seperti yang lainnya.

df.dtypes
A    object  # you DON'T want this
B    object
C    object
dtype: object

Menambahkan masih memiliki semua masalah seperti metode di atas.

for i, (a, b, c) in enumerate(some_function_that_yields_data()):
    df.iloc[i] = [a, b, c]

Bukti ada di Puding

Mengatur waktu metode-metode ini adalah cara tercepat untuk melihat seberapa jauh mereka berbeda dalam hal memori dan utilitas mereka.

masukkan deskripsi gambar di sini

Kode benchmark untuk referensi.

cs95
sumber
6
Daftar tambahkan harus menjadi cara terbaik untuk jenis pertanyaan ini
YOBEN_S
9
Ini perlu ditingkatkan satu juta kali lebih banyak. Jangan pernah menumbuhkan kerangka data!
Buggy
3
@ user3293236 Sayang sekali Anda harus mulai dari bawah setiap kali Anda menjawab pertanyaan lama;)
cs95
2
Ini adalah salah satu hal yang paling saya benci. Sering kali Anda melihat ๐’“๐’†๐’‚๐’ ๐’„๐’๐’“๐’“๐’†๐’„๐’• ๐’‚๐’๐’”๐’˜๐’†๐’“ yang hanya tinggal di suatu tempat dengan sedikit suara dan tidak pernah diterima. Saya kehilangan kode dengan ๐š๐š = ๐š™๐š.๐™ณ๐šŠ๐š๐šŠ๐™ต๐š›๐šŠ๐š–๐šŽ ([]) untuk membuat kerangka data panda kosong. Benarkan jawaban ini. Penjelasan luar biasa, @ cs95!
Jonathan
1
Ini secara harfiah dalam dokumentasi. "Iteratif menambahkan baris ke DataFrame bisa lebih intensif secara komputasi daripada satu rangkaian. Solusi yang lebih baik adalah menambahkan baris-baris itu ke daftar dan kemudian menggabungkan daftar dengan DataFrame asli sekaligus." pandas.pydata.org/pandas-docs/version/0.21/generated/โ€ฆ
endolith
132

Inisialisasi bingkai kosong dengan nama kolom

import pandas as pd

col_names =  ['A', 'B', 'C']
my_df  = pd.DataFrame(columns = col_names)
my_df

Tambahkan catatan baru ke bingkai

my_df.loc[len(my_df)] = [2, 4, 5]

Anda juga mungkin ingin melewati kamus:

my_dic = {'A':2, 'B':4, 'C':5}
my_df.loc[len(my_df)] = my_dic 

Tambahkan bingkai lain ke bingkai Anda yang ada

col_names =  ['A', 'B', 'C']
my_df2  = pd.DataFrame(columns = col_names)
my_df = my_df.append(my_df2)

Pertimbangan kinerja

Jika Anda menambahkan baris di dalam satu lingkaran pertimbangkan masalah kinerja. Untuk sekitar 1000 rekaman pertama "my_df.loc" kinerja lebih baik, tetapi secara bertahap menjadi lebih lambat dengan menambah jumlah catatan dalam loop.

Jika Anda berencana untuk melakukan thins di dalam satu lingkaran besar (katakanlah 10Mโ€Œ record atau lebih), Anda lebih baik menggunakan campuran keduanya; isi dataframe dengan iloc sampai ukurannya mencapai sekitar 1000, lalu tambahkan ke dataframe asli, dan kosongkan temp dataframe. Ini akan meningkatkan kinerja Anda sekitar 10 kali.

Afshin Amiri
sumber
my_df = my_df.append(my_df2)tidak bekerja untuk saya kecuali saya tentukan ignore_index=True.
Nasif Imtiaz Ohi
0

Asumsikan kerangka data dengan 19 baris

index=range(0,19)
index

columns=['A']
test = pd.DataFrame(index=index, columns=columns)

Menjaga Kolom A sebagai konstanta

test['A']=10

Menyimpan kolom b sebagai variabel yang diberikan oleh sebuah loop

for x in range(0,19):
    test.loc[[x], 'b'] = pd.Series([x], index = [x])

Anda dapat mengganti x pertama pd.Series([x], index = [x])dengan nilai apa pun

Ajay Ohri
sumber