Latar belakang singkat: Banyak (kebanyakan?) Bahasa pemrograman kontemporer yang digunakan secara luas memiliki setidaknya beberapa ADT [tipe data abstrak] yang sama, khususnya,
string (urutan terdiri dari karakter)
daftar (koleksi nilai yang dipesan), dan
tipe berbasis peta (array tidak berurutan yang memetakan kunci nilai)
Dalam bahasa pemrograman R, dua yang pertama diimplementasikan sebagai character
dan vector
, masing-masing.
Ketika saya mulai belajar R, dua hal sudah jelas hampir dari awal: list
adalah tipe data yang paling penting dalam R (karena itu adalah kelas induk untuk R data.frame
), dan kedua, saya tidak bisa mengerti bagaimana mereka bekerja, setidaknya tidak cukup baik untuk menggunakannya dengan benar dalam kode saya.
Untuk satu hal, menurut saya list
tipe data R adalah implementasi langsung dari peta ADT ( dictionary
dalam Python, NSMutableDictionary
di Objective C, hash
di Perl dan Ruby, object literal
di Javascript, dan sebagainya).
Misalnya, Anda membuatnya sama seperti kamus Python, dengan meneruskan pasangan nilai kunci ke konstruktor (yang dalam Python dict
tidak list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Dan Anda mengakses item dari Daftar R sama seperti Anda dengan orang-orang dari kamus Python, misalnya x['ev1']
,. Demikian juga, Anda dapat mengambil hanya 'kunci' atau hanya 'nilai' dengan:
names(x) # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"
unlist(x) # fetch just the 'values' of an R list
# ev1 ev2 rv
# "10" "15" "Group 1"
x = list("a"=6, "b"=9, "c"=3)
sum(unlist(x))
# [1] 18
tetapi R list
juga tidak seperti ADT tipe peta lainnya (dari antara bahasa yang saya pelajari). Dugaan saya adalah bahwa ini adalah konsekuensi dari spesifikasi awal untuk S, yaitu niat untuk merancang data / statistik DSL [bahasa khusus domain] dari bawah ke atas.
tiga perbedaan signifikan antara R list
s dan tipe pemetaan dalam bahasa lain dalam penggunaan luas (mis., Python, Perl, JavaScript):
pertama , list
s dalam R adalah koleksi yang diurutkan , seperti vektor, meskipun nilainya dikunci (yaitu, kunci dapat berupa nilai hashable bukan hanya bilangan bulat berurutan). Hampir selalu, tipe data pemetaan dalam bahasa lain tidak berurutan .
kedua , list
s dapat dikembalikan dari fungsi meskipun Anda tidak pernah melewati list
ketika Anda memanggil fungsi, dan meskipun fungsi yang mengembalikan list
tidak mengandung list
konstruktor ( eksplisit) (Tentu saja, Anda dapat menangani ini dalam praktik dengan membungkus hasil yang dikembalikan dalam panggilan ke unlist
):
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x) # returns 'list', not a vector of length 2
# [1] list
Sebuah ketiga fitur khas R list
s: itu tidak tampak bahwa mereka dapat menjadi anggota ADT lain, dan jika Anda mencoba untuk melakukan itu maka wadah primer dipaksa untuk list
. Misalnya,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
maksud saya di sini bukan untuk mengkritik bahasa atau bagaimana bahasa itu didokumentasikan; juga, saya tidak menyarankan ada yang salah dengan list
struktur data atau bagaimana perilakunya. Yang saya cari hanyalah mengoreksi pemahaman saya tentang cara kerjanya sehingga saya dapat menggunakannya dengan benar dalam kode saya.
Berikut adalah beberapa hal yang saya ingin lebih mengerti:
Apa aturan yang menentukan kapan pemanggilan fungsi akan mengembalikan
list
(misalnya,strsplit
ekspresi dilafalkan di atas)?Jika saya tidak secara eksplisit menetapkan nama ke
list
(misalnya,list(10,20,30,40)
) apakah nama default hanyalah bilangan bulat berurutan yang dimulai dengan 1? (Saya berasumsi, tapi saya jauh dari yakin bahwa jawabannya adalah ya, kalau tidak kita tidak akan bisa memaksa jenis inilist
ke vektor dengan panggilanunlist
).Mengapa dua operator yang berbeda ini
[]
,, dan[[]]
, mengembalikan hasil yang sama ?x = list(1, 2, 3, 4)
kedua ekspresi menghasilkan "1":
x[1]
x[[1]]
mengapa kedua ungkapan ini tidak memberikan hasil yang sama?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Tolong jangan arahkan saya ke Dokumentasi R ( ?list
, R-intro
) - Saya telah membacanya dengan seksama dan itu tidak membantu saya menjawab jenis pertanyaan yang saya baca di atas.
(terakhir, saya baru-baru ini belajar dan mulai menggunakan Paket R (tersedia di CRAN) yang disebut hash
yang mengimplementasikan perilaku tipe peta konvensional melalui kelas S4; Saya pasti dapat merekomendasikan Paket ini.)
x = list(1, 2, 3, 4)
, keduanya TIDAK mengembalikan hasil yang sama:,x[1]
danx[[1]]
. Yang pertama mengembalikan daftar dan yang kedua mengembalikan vektor numerik. Dengan menggulir ke bawah, saya melihat bahwa Dirk adalah satu-satunya responden yang menjawab pertanyaan ini dengan benar.list
di R tidak seperti hash. Saya punya satu lagi yang menurut saya layak untuk dicatat.list
di R dapat memiliki dua anggota dengan nama referensi yang sama. Pertimbangkan ituobj <- c(list(a=1),list(a=2))
valid dan mengembalikan daftar dengan dua nilai bernama 'a'. Dalam hal ini panggilan untukobj["a"]
hanya akan mengembalikan elemen daftar pencocokan pertama. Anda bisa mendapatkan perilaku yang mirip (mungkin identik) dengan hash dengan hanya satu item per nama yang direferensikan menggunakan lingkungan dalam R. misalnyax <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
Jawaban:
Hanya untuk menjawab bagian terakhir dari pertanyaan Anda, karena itu benar-benar menunjukkan perbedaan antara a
list
danvector
di R:Daftar dapat berisi kelas lain karena setiap elemen. Jadi Anda dapat memiliki daftar di mana elemen pertama adalah vektor karakter, yang kedua adalah bingkai data, dll. Dalam hal ini, Anda telah membuat dua daftar yang berbeda.
x
memiliki empat vektor, masing-masing panjang 1.x2
memiliki 1 vektor panjang 4:Jadi ini adalah daftar yang sangat berbeda.
Daftar R sangat mirip struktur data peta hash di mana setiap nilai indeks dapat dikaitkan dengan objek apa pun. Berikut adalah contoh sederhana dari daftar yang berisi 3 kelas berbeda (termasuk fungsi):
Mengingat bahwa elemen terakhir adalah fungsi pencarian, saya dapat menyebutnya seperti ini:
Sebagai komentar terakhir tentang ini: perlu dicatat bahwa a
data.frame
benar-benar daftar (daridata.frame
dokumentasi):Itu sebabnya kolom dalam a
data.frame
dapat memiliki tipe data yang berbeda, sedangkan kolom dalam matriks tidak bisa. Sebagai contoh, di sini saya mencoba membuat matriks dengan angka dan karakter:Perhatikan bagaimana saya tidak bisa mengubah tipe data di kolom pertama menjadi numerik karena kolom kedua memiliki karakter:
sumber
switch
fungsi yang berguna dalam R yang dapat digunakan untuk tujuan itu (lihathelp(switch)
).Mengenai pertanyaan Anda, izinkan saya mengatasinya secara berurutan dan berikan beberapa contoh:
1 ) Daftar dikembalikan jika dan ketika pernyataan kembali menambahkan satu. Mempertimbangkan
2 ) Nama tidak disetel:
3 ) Mereka tidak mengembalikan hal yang sama. Teladan Anda memberi
di mana
x[1]
mengembalikan elemen pertamax
- yang sama denganx
. Setiap skalar adalah vektor dengan panjang satu. Di sisi lainx[[1]]
mengembalikan elemen pertama dari daftar.4 ) Terakhir, keduanya berbeda antara yang mereka buat, masing-masing, daftar yang berisi empat skalar dan daftar dengan elemen tunggal (yang kebetulan merupakan vektor dari empat elemen).
sumber
Value
. Seperti di?strsplit
: "Daftar dengan panjang yang sama dengan x". Tetapi Anda harus mempertimbangkan bahwa mungkin ada fungsi mengembalikan nilai yang berbeda tergantung pada argumen (mis. Sapply dapat mengembalikan daftar atau vektor).Hanya untuk mengambil sebagian dari pertanyaan Anda:
Artikel tentang pengindeksan ini membahas pertanyaan tentang perbedaan antara
[]
dan[[]]
.Singkatnya [[]] memilih satu item dari daftar dan
[]
mengembalikan daftar item yang dipilih. Dalam contoh Anda,x = list(1, 2, 3, 4)'
item 1 adalah bilangan bulat tunggal tetapix[[1]]
mengembalikan satu 1 danx[1]
mengembalikan daftar dengan hanya satu nilai.sumber
A = array( 11:16, c(2,3) ); A[5]
apakah 15, dalam susunan datar ?!Salah satu alasan daftar berfungsi sebagaimana mestinya (dipesan) adalah untuk menjawab kebutuhan akan wadah yang dipesan yang dapat berisi jenis apa pun di simpul mana pun, yang tidak dilakukan oleh vektor. Daftar digunakan kembali untuk berbagai keperluan dalam R, termasuk membentuk dasar dari a
data.frame
, yang merupakan daftar vektor jenis sewenang-wenang (tetapi panjangnya sama).Mengapa kedua ungkapan ini tidak memberikan hasil yang sama?
Untuk menambahkan jawaban @ Shane, jika Anda ingin mendapatkan hasil yang sama, cobalah:
Yang memaksa vektor
1:4
menjadi daftar.sumber
Tambahkan satu poin lagi ke sini:
R memang memiliki struktur data setara dengan dict Python di dalam
hash
paket . Anda dapat membacanya di posting blog ini dari Open Data Group . Berikut ini contoh sederhana:Dalam hal kegunaan,
hash
kelasnya sangat mirip dengan daftar. Tetapi kinerjanya lebih baik untuk dataset besar.sumber
Kamu bilang:
Dan saya kira Anda menyarankan bahwa ini adalah masalah (?). Saya di sini untuk memberi tahu Anda mengapa ini bukan masalah :-). Contoh Anda agak sederhana, ketika Anda melakukan string-split, Anda memiliki daftar dengan elemen yang panjangnya 1 elemen, jadi Anda tahu bahwa
x[[1]]
itu sama denganunlist(x)[1]
. Tetapi bagaimana jika hasil yangstrsplit
dikembalikan menghasilkan panjang yang berbeda di setiap nampan. Cukup mengembalikan vektor (vs. daftar) tidak akan berhasil sama sekali.Misalnya:
Dalam kasus pertama (
x
: yang mengembalikan daftar), Anda dapat memberitahu apa-2 "bagian" dari string 3 adalah, misalnya:x[[3]][2]
. Bagaimana Anda bisa melakukan hal yang sama menggunakanxx
sekarang bahwa hasilnya telah "diurai" (unlist
-ed)?sumber
tidak sama karena 1: 4 sama dengan c (1,2,3,4). Jika Anda ingin mereka sama maka:
sumber
Ini adalah pertanyaan yang sangat lama, tetapi saya pikir jawaban baru mungkin menambah nilai karena, menurut pendapat saya, tidak ada yang secara langsung mengatasi beberapa masalah dalam OP.
Terlepas dari apa yang diterima oleh jawaban yang disarankan,
list
objek dalam R bukan peta hash. Jika Anda ingin membuat paralel dengan python,list
lebih seperti, Anda dapat menebak, pythonlist
s (atautuple
s sebenarnya).Lebih baik untuk menggambarkan bagaimana sebagian besar objek R disimpan secara internal (tipe C dari objek R adalah
SEXP
). Mereka pada dasarnya terbuat dari tiga bagian:NULL
jika objek tidak memiliki atribut).Dari sudut pandang internal, ada sedikit perbedaan antara a
list
dannumeric
vektor misalnya. Nilai-nilai yang mereka simpan hanya berbeda. Mari kita pecahkan dua objek ke dalam paradigma yang telah kita gambarkan sebelumnya:Untuk
x
:numeric
(REALSXP
di sisi-C), panjangnya 10 dan hal-hal lainnya.double
nilai.NULL
, karena objek tidak punya.Untuk
y
:list
(VECSXP
di sisi-C), panjangnya 2 dan lainnya.runif(10)
danrunif(3)
masing - masing.NULL
, seperti untukx
.Jadi satu-satunya perbedaan antara
numeric
vektor dan alist
adalah bahwa bagiannumeric
data terbuat daridouble
nilai, sedangkan untuklist
bagian data adalah array pointer ke objek R lainnya.Apa yang terjadi dengan nama? Nah, nama hanyalah beberapa atribut yang dapat Anda tetapkan untuk suatu objek. Mari kita lihat objek di bawah ini:
list
(VECSXP
di sisi-C), panjangnya 2 dan lainnya.1:3
danLETTERS
masing - masing.names
komponen yang merupakancharacter
objek R dengan nilaic("a","b")
.Dari level R, Anda dapat mengambil atribut suatu objek dengan
attributes
fungsinya.Nilai kunci khas dari peta hash di R hanyalah ilusi. Ketika Anda mengatakan:
Inilah yang terjadi:
[[
fungsi bagian ini disebut;"a"
) adalah tipecharacter
, jadi metode ini diinstruksikan untuk mencari nilai tersebut darinames
atribut (jika ada) objekz
;names
atribut tidak ada,NULL
dikembalikan;"a"
nilai dicari di dalamnya. Jika"a"
bukan nama objek,NULL
dikembalikan;z[[1]]
.Pencarian nilai kunci agak tidak langsung dan selalu posisional. Juga, berguna untuk diingat:
names
dalam R harus berupa string (character
vektor);di peta hash Anda tidak dapat memiliki dua kunci yang identik. Di R, Anda bisa menetapkan
names
ke objek dengan nilai berulang. Misalnya:sangat valid dalam R. Ketika Anda mencoba
y[["same"]]
nilai pertama diambil. Anda harus tahu mengapa pada titik ini.Sebagai kesimpulan, kemampuan untuk memberikan atribut sewenang-wenang kepada suatu objek memberi Anda penampilan sesuatu yang berbeda dari sudut pandang eksternal. Tapi Rs
list
bukan peta hash dengan cara apa pun.sumber
Mengenai vektor dan konsep hash / array dari bahasa lain:
Vektor adalah atom-atom R. Eg,
rpois(1e4,5)
(5 angka acak),numeric(55)
(panjang-55 vektor nol lebih dari dua kali lipat), dancharacter(12)
(12 string kosong), semuanya "dasar".Entah daftar atau vektor dapat memiliki
names
.Vektor membutuhkan semuanya untuk tipe data yang sama. Menonton ini:
Daftar dapat berisi berbagai tipe data, seperti terlihat pada jawaban lain dan pertanyaan OP sendiri.
Saya telah melihat bahasa (ruby, javascript) di mana "array" dapat berisi tipe data variabel, tetapi misalnya dalam C ++ "array" harus semua tipe data yang sama. Saya percaya ini adalah hal kecepatan / efisiensi: jika Anda memiliki
numeric(1e6)
Anda tahu ukurannya dan lokasi setiap elemen a priori ; jika benda itu mengandung"Flying Purple People Eaters"
beberapa irisan yang tidak diketahui, maka Anda harus benar-benar menguraikan hal-hal untuk mengetahui fakta dasar tentangnya.Operasi R standar tertentu juga lebih masuk akal ketika jenisnya dijamin. Misalnya
cumsum(1:9)
masuk akal sedangkancumsum(list(1,2,3,4,5,'a',6,7,8,9))
tidak, tanpa jenis yang dijamin ganda.Adapun pertanyaan kedua Anda:
Fungsi mengembalikan tipe data yang berbeda dari yang mereka masukan sepanjang waktu.
plot
mengembalikan plot meskipun tidak mengambil plot sebagai input.Arg
mengembalikannumeric
meskipun diterima acomplex
. Dll(Dan untuk
strsplit
: kode sumber ada di sini .)sumber
Meskipun ini adalah pertanyaan yang cukup lama, saya harus mengatakan bahwa itu menyentuh persis pengetahuan yang saya lewatkan selama langkah pertama saya di R - yaitu bagaimana mengekspresikan data di tangan saya sebagai objek di R atau bagaimana memilih dari objek yang ada. Tidak mudah bagi seorang pemula untuk berpikir "dalam kotak R" sejak awal.
Jadi saya sendiri mulai menggunakan kruk di bawah ini yang banyak membantu saya untuk mencari tahu objek apa yang digunakan untuk data apa, dan pada dasarnya untuk membayangkan penggunaan dunia nyata.
Meskipun saya tidak memberikan jawaban yang tepat untuk pertanyaan, teks pendek di bawah ini dapat membantu pembaca yang baru mulai dengan R dan mengajukan pertanyaan serupa.
[
himpunan bagian.[
himpunan bagian.[
himpunan bagian dengan baris dan kolom, atau dengan urutan.list
mana saya dapat subset menggunakan[
baris dan kolom, tetapi bahkan menggunakan[[
.tree structure
mana[i]
memilih dan mengembalikan seluruh cabang dan[[i]]
mengembalikan item dari cabang. Dan karena itutree like structure
, Anda bahkan dapat menggunakanindex sequence
untuk mengatasi setiap daun tunggal pada sangat komplekslist
menggunakan nya[[index_vector]]
. Daftar dapat sederhana atau sangat kompleks dan dapat mencampur berbagai jenis objek menjadi satu.Jadi bagi
lists
Anda dapat berakhir dengan lebih banyak cara bagaimana memilihleaf
tergantung pada situasi seperti dalam contoh berikut.Cara berpikir seperti ini banyak membantu saya.
sumber
Jika itu membantu, saya cenderung menganggap "daftar" dalam R sebagai "catatan" dalam bahasa pra-OO lainnya:
Nama "catatan" akan berbenturan dengan makna standar "catatan" (alias baris) dalam bahasa database, dan mungkin inilah sebabnya nama mereka menyarankan dirinya: sebagai daftar (bidang).
sumber
mengapa dua operator yang berbeda ini
[ ]
,, dan[[ ]]
, mengembalikan hasil yang sama?[ ]
menyediakan operasi pengaturan sub. Secara umum sub set objek apa pun akan memiliki tipe yang sama dengan objek aslinya. Karena itu,x[1]
sediakan daftar. Demikian pulax[1:2]
subset dari daftar asli, oleh karena itu adalah daftar. Ex.[[ ]]
adalah untuk mengekstraksi elemen dari daftar.x[[1]]
valid dan ekstrak elemen pertama dari daftar.x[[1:2]]
tidak valid karena[[ ]]
tidak menyediakan sub pengaturan seperti[ ]
.sumber