Saya ingin membuat dataframe baris demi baris di R. Saya telah melakukan beberapa pencarian, dan yang saya dapatkan hanyalah saran untuk membuat daftar kosong, menyimpan skalar indeks daftar, lalu setiap kali menambahkan ke daftar kerangka data baris tunggal dan memajukan indeks daftar satu per satu. Akhirnya, do.call(rbind,)
masuk dalam daftar.
Meskipun ini berhasil, tampaknya sangat tidak praktis. Bukankah ada cara yang lebih mudah untuk mencapai tujuan yang sama?
Jelas saya mengacu pada kasus di mana saya tidak dapat menggunakan beberapa apply
fungsi dan secara eksplisit perlu membuat dataframe baris demi baris. Setidaknya, apakah ada cara untuk push
memasuki akhir daftar daripada secara eksplisit melacak indeks terakhir yang digunakan?
append()
[yang mungkin harus diberi nama sisipkan] atauc()
untuk menambahkan item ke akhir daftar, meskipun tidak akan membantu Anda di sini.lapply()
,Map()
, dan sebagainya, tetapi Anda juga mungkin ingin melihat padaaggregate()
,dapply() {heR.Misc}
, dancast() {reshape}
untuk melihat apakah tugas-tugas Anda tidak dapat ditangani oleh ini fungsi (ini semua frame data kembali).Jawaban:
Anda dapat mengembangkannya baris demi baris dengan menambahkan atau menggunakan
rbind()
.Itu tidak berarti Anda harus melakukannya. Struktur yang tumbuh secara dinamis adalah salah satu cara yang paling tidak efisien untuk membuat kode di R.
Jika Anda bisa, alokasikan seluruh data.frame Anda di muka:
dan kemudian selama operasi Anda masukkan baris pada satu waktu
Itu seharusnya berfungsi untuk data.frame sewenang-wenang dan jauh lebih efisien. Jika Anda melampaui N, Anda selalu dapat memperkecil baris kosong di bagian akhir.
sumber
data.table
tampaknya lebih cepat daripada pra-alokasi menggunakan data.frames. Pengujian di sini: stackoverflow.com/a/11486400/636656Seseorang dapat menambahkan baris ke
NULL
:misalnya
sumber
sapply
(atau melakukan vektorisasi) dan mentransposisi.Ini adalah contoh konyol bagaimana menggunakan
do.call(rbind,)
pada keluaranMap()
[yang mirip denganlapply()
]Saya cukup sering menggunakan konstruksi ini.
sumber
Alasan saya sangat menyukai Rcpp adalah karena saya tidak selalu mengerti cara berpikir R Core, dan dengan Rcpp, lebih sering daripada tidak, saya tidak perlu melakukannya.
Berbicara secara filosofis, Anda berada dalam keadaan berdosa sehubungan dengan paradigma fungsional, yang mencoba memastikan bahwa setiap nilai muncul terlepas dari setiap nilai lainnya; mengubah satu nilai tidak boleh menyebabkan perubahan yang terlihat di nilai lain, seperti yang Anda dapatkan dengan representasi berbagi pointer di C.
Masalah muncul ketika pemrograman fungsional memberi sinyal pada pesawat kecil untuk menyingkir, dan pesawat kecil itu menjawab "Saya adalah mercusuar". Membuat serangkaian panjang perubahan kecil pada objek besar yang ingin Anda proses sementara itu membuat Anda persegi di wilayah mercusuar.
Dalam C ++ STL,
push_back()
adalah cara hidup. Itu tidak mencoba untuk berfungsi, tetapi mencoba untuk mengakomodasi idiom pemrograman umum secara efisien .Dengan beberapa kepintaran di balik layar, terkadang Anda dapat mengatur agar memiliki satu kaki di setiap dunia. Sistem file berbasis snapshot adalah contoh yang baik (yang berevolusi dari konsep seperti union mount, yang juga menggunakan kedua sisi).
Jika R Core ingin melakukan ini, penyimpanan vektor yang mendasari dapat berfungsi seperti union mount. Satu referensi ke penyimpanan vektor mungkin valid untuk langganan
1:N
, sementara referensi lain ke penyimpanan yang sama berlaku untuk langganan1:(N+1)
. Mungkin ada penyimpanan yang dipesan belum secara valid direferensikan oleh apa pun kecuali nyaman untuk cepatpush_back()
. Anda tidak melanggar konsep fungsional saat menambahkan di luar rentang yang dianggap valid oleh referensi yang ada.Akhirnya menambahkan baris secara bertahap, Anda kehabisan penyimpanan yang dipesan. Anda harus membuat salinan baru dari semuanya, dengan penyimpanan dikalikan dengan beberapa kenaikan. Implementasi STL yang saya gunakan cenderung melipatgandakan penyimpanan dengan 2 saat memperluas alokasi. Saya pikir saya membaca di R Internal bahwa ada struktur memori di mana penyimpanan bertambah 20%. Bagaimanapun, operasi pertumbuhan terjadi dengan frekuensi logaritmik relatif terhadap jumlah total elemen yang ditambahkan. Secara diamortisasi, ini biasanya dapat diterima.
Saat trik di balik layar berjalan, saya telah melihat yang lebih buruk. Setiap kali Anda
push_back()
membuat baris baru ke dataframe, struktur indeks tingkat atas perlu disalin. Baris baru dapat ditambahkan ke representasi bersama tanpa memengaruhi nilai fungsional lama apa pun. Saya bahkan tidak berpikir itu akan mempersulit pemulung; karena saya tidak mengusulkanpush_front()
semua referensi adalah referensi awalan ke depan penyimpanan vektor yang dialokasikan.sumber
Jawaban Dirk Eddelbuettel adalah yang terbaik; di sini saya hanya mencatat bahwa Anda dapat lolos dengan tidak menentukan dimensi kerangka data atau tipe data sebelumnya, yang terkadang berguna jika Anda memiliki beberapa tipe data dan banyak kolom:
sumber
df<-rbind(df, row2)
?Saya telah menemukan cara ini untuk membuat kerangka data dengan mentah tanpa matriks.
Dengan nama kolom otomatis
Dengan nama kolom
sumber
Jika Anda memiliki vektor yang ditakdirkan menjadi baris, gabungkan menggunakan
c()
, teruskan ke matriks baris demi baris, dan konversikan matriks tersebut ke kerangka data.Misalnya baris
dapat diubah menjadi bingkai data dengan demikian:
Memang, saya melihat 2 batasan utama: (1) ini hanya berfungsi dengan data mode tunggal, dan (2) Anda harus mengetahui # kolom terakhir Anda agar ini berfungsi (yaitu, saya berasumsi bahwa Anda tidak bekerja dengan larik compang-camping yang panjang baris terbesarnya tidak diketahui secara a priori ).
Solusi ini tampaknya sederhana, tetapi dari pengalaman saya dengan jenis konversi di R, saya yakin ini menciptakan tantangan baru di masa mendatang. Adakah yang bisa mengomentari ini?
sumber
Bergantung pada format baris baru Anda, Anda dapat menggunakan
tibble::add_row
jika baris baru Anda sederhana dan dapat ditentukan dalam "pasangan nilai". Atau Anda bisa menggunakandplyr::bind_rows
, "implementasi yang efisien dari pola umum do.call (rbind, dfs)".sumber