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 dtypes
disimpulkan secara otomatis (daripada menugaskan object
mereka semua).
Keuntungan terakhir adalah bahwa a RangeIndex
secara otomatis dibuat untuk data Anda , jadi itu adalah satu hal yang kurang perlu dikhawatirkan (lihat pada orang miskin append
dan loc
metode di bawah ini, Anda akan melihat elemen di keduanya yang memerlukan penanganan indeks dengan tepat).
Hal-hal yang TIDAK BISA Anda lakukan
append
atau concat
di 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 append
atau concat
operasi yang Anda miliki. Pasangkan ini dengan satu lingkaran dan Anda memiliki operasi kompleksitas kuadratik . Dari df.append
halaman 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.append
adalah 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 loc
digunakan 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.
Kode benchmark untuk referensi.