Jawaban:
Definisi Bahasa R berguna untuk menjawab jenis pertanyaan ini:
R memiliki tiga operator pengindeksan dasar, dengan sintaksis ditampilkan oleh contoh-contoh berikut
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
Untuk vektor dan matriks
[[
formulir jarang digunakan, meskipun mereka memiliki beberapa perbedaan semantik kecil dari[
formulir (misalnya menjatuhkan nama atau atribut nama dimnames, dan bahwa pencocokan sebagian digunakan untuk indeks karakter). Saat mengindeks struktur multi-dimensi dengan indeks tunggal,x[[i]]
ataux[i]
akan mengembalikani
elemen sekuensialx
.Untuk daftar, biasanya digunakan
[[
untuk memilih elemen tunggal, sedangkan[
mengembalikan daftar elemen yang dipilih.The
[[
Bentuk memungkinkan hanya satu elemen yang akan dipilih menggunakan integer atau karakter indeks, sedangkan[
memungkinkan pengindeksan oleh vektor. Perhatikan bahwa untuk suatu daftar, indeks dapat berupa vektor dan setiap elemen vektor diterapkan secara bergiliran ke daftar, komponen yang dipilih, komponen yang dipilih dari komponen itu, dan seterusnya. Hasilnya masih satu elemen.
[
selalu kembali daftar berarti bahwa Anda mendapatkan kelas output yang sama untuk x[v]
terlepas dari panjang v
. Misalnya, satu mungkin ingin lapply
over subset dari daftar: lapply(x[v], fun)
. Jika [
akan menjatuhkan daftar untuk vektor panjang satu, ini akan mengembalikan kesalahan setiap kali v
memiliki panjang satu.
Perbedaan signifikan antara kedua metode adalah kelas objek yang mereka kembalikan saat digunakan untuk ekstraksi dan apakah mereka dapat menerima rentang nilai, atau hanya nilai tunggal selama penugasan.
Pertimbangkan kasus ekstraksi data pada daftar berikut:
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
Katakanlah kami ingin mengekstrak nilai yang disimpan oleh bool dari foo dan menggunakannya di dalam if()
pernyataan. Ini akan menggambarkan perbedaan antara nilai-nilai pengembalian []
dan [[]]
ketika mereka digunakan untuk ekstraksi data. The []
kembali metode objek dari daftar kelas (atau data.frame jika foo adalah data.frame a) sedangkan [[]]
metode kembali objek yang kelasnya ditentukan oleh jenis nilai-nilai mereka.
Jadi, menggunakan []
metode menghasilkan sebagai berikut:
if( foo[ 'bool' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical
class( foo[ 'bool' ] )
[1] "list"
Ini karena []
metode mengembalikan daftar dan daftar bukan objek yang valid untuk diteruskan langsung ke if()
pernyataan. Dalam hal ini kita perlu menggunakan [[]]
karena akan mengembalikan objek "telanjang" yang disimpan dalam 'bool' yang akan memiliki kelas yang sesuai:
if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"
class( foo[[ 'bool' ]] )
[1] "logical"
Perbedaan kedua adalah bahwa []
operator dapat digunakan untuk mengakses berbagai slot dalam daftar atau kolom dalam bingkai data sementara [[]]
operator dibatasi untuk mengakses slot atau kolom tunggal . Pertimbangkan kasus nilai tugas menggunakan daftar kedua, bar()
:
bar <- list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) )
Katakanlah kita ingin menimpa dua slot foo terakhir dengan data yang terkandung dalam bilah. Jika kami mencoba menggunakan [[]]
operator, inilah yang terjadi:
foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar :
more elements supplied than there are to replace
Ini karena [[]]
terbatas untuk mengakses elemen tunggal. Kita perlu menggunakan []
:
foo[ 2:3 ] <- bar
print( foo )
$str
[1] "R"
$vec
[,1] [,2]
[1,] 0 0
[2,] 0 0
$bool
[1] -0.6291121
Perhatikan bahwa sementara tugas berhasil, slot di foo menyimpan nama asli mereka.
Kurung ganda mengakses elemen daftar , sementara braket tunggal memberi Anda kembali daftar dengan elemen tunggal.
lst <- list('one','two','three')
a <- lst[1]
class(a)
## returns "list"
a <- lst[[1]]
class(a)
## returns "character"
Dari Hadley Wickham:
Modifikasi (tampak jelek) saya untuk ditampilkan menggunakan tidyverse / purrr:
[]
ekstrak daftar, [[]]
ekstrak elemen dalam daftar
alist <- list(c("a", "b", "c"), c(1,2,3,4), c(8e6, 5.2e9, -9.3e7))
str(alist[[1]])
chr [1:3] "a" "b" "c"
str(alist[1])
List of 1
$ : chr [1:3] "a" "b" "c"
str(alist[[1]][1])
chr "a"
Hanya menambahkan di sini yang [[
juga dilengkapi untuk pengindeksan rekursif .
Ini diisyaratkan dalam jawaban oleh @JijoMatthew tetapi tidak dieksplorasi.
Seperti disebutkan dalam ?"[["
, sintaksis like x[[y]]
, where length(y) > 1
, diartikan sebagai:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
Perhatikan bahwa ini tidak mengubah apa yang seharusnya menjadi takeaway utama Anda pada perbedaan antara [
dan [[
- yaitu, bahwa yang pertama digunakan untuk subset , dan yang terakhir digunakan untuk mengekstraksi elemen daftar tunggal.
Sebagai contoh,
x <- list(list(list(1), 2), list(list(list(3), 4), 5), 6)
x
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] 1
#
# [[1]][[2]]
# [1] 2
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [[2]][[1]][[1]][[1]]
# [1] 3
#
# [[2]][[1]][[2]]
# [1] 4
#
# [[2]][[2]]
# [1] 5
#
# [[3]]
# [1] 6
Untuk mendapatkan nilai 3, kita bisa melakukan:
x[[c(2, 1, 1, 1)]]
# [1] 3
Kembali ke jawaban JijoMatthew di atas, ingat r
:
r <- list(1:10, foo=1, far=2)
Secara khusus, ini menjelaskan kesalahan yang cenderung kita dapatkan ketika salah menggunakan [[
, yaitu:
r[[1:3]]
Kesalahan dalam
r[[1:3]]
: pengindeksan rekursif gagal di level 2
Karena kode ini benar-benar mencoba untuk mengevaluasi r[[1]][[2]][[3]]
, dan bersarangnya r
stop pada level satu, upaya untuk mengekstraksi melalui pengindeksan rekursif gagal pada [[2]]
, yaitu, pada level 2.
Kesalahan dalam
r[[c("foo", "far")]]
: subskrip di luar batas
Di sini, R sedang mencari r[["foo"]][["far"]]
, yang tidak ada, jadi kami mendapatkan subscript dari kesalahan batas.
Mungkin akan sedikit lebih membantu / konsisten jika kedua kesalahan ini memberikan pesan yang sama.
Keduanya merupakan cara subset. Braket tunggal akan mengembalikan subset dari daftar, yang dengan sendirinya akan menjadi daftar. yaitu: Ini mungkin atau mungkin tidak mengandung lebih dari satu elemen. Di sisi lain braket ganda akan mengembalikan hanya satu elemen dari daftar.
Braket -Single akan memberi kita daftar. Kami juga dapat menggunakan braket tunggal jika kami ingin mengembalikan beberapa elemen dari daftar. pertimbangkan daftar berikut: -
>r<-list(c(1:10),foo=1,far=2);
Sekarang tolong perhatikan cara mengembalikan daftar ketika saya mencoba untuk menampilkannya. Saya ketik r dan tekan enter
>r
#the result is:-
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
Sekarang kita akan melihat keajaiban braket tunggal: -
>r[c(1,2,3)]
#the above command will return a list with all three elements of the actual list r as below
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
yang persis sama dengan ketika kami mencoba untuk menampilkan nilai r pada layar, yang berarti penggunaan braket tunggal telah mengembalikan daftar, di mana pada indeks 1 kami memiliki vektor 10 elemen, maka kami memiliki dua elemen lagi dengan nama foo dan jauh. Kami juga dapat memilih untuk memberikan indeks tunggal atau nama elemen sebagai input ke braket tunggal. misalnya:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
Dalam contoh ini kami memberikan satu indeks "1" dan sebagai gantinya mendapat daftar dengan satu elemen (yang merupakan array dari 10 angka)
> r[2]
$foo
[1] 1
Pada contoh di atas kami memberikan satu indeks "2" dan sebagai gantinya mendapat daftar dengan satu elemen
> r["foo"];
$foo
[1] 1
Dalam contoh ini kami memberikan nama satu elemen dan sebagai balasannya daftar dikembalikan dengan satu elemen.
Anda juga dapat melewati vektor nama elemen seperti: -
> x<-c("foo","far")
> r[x];
$foo
[1] 1
$far
[1] 2
Dalam contoh ini kami melewati vektor dengan dua nama elemen "foo" dan "jauh"
Sebagai gantinya kami mendapat daftar dengan dua elemen.
Singkatnya braket tunggal akan selalu mengembalikan Anda daftar lain dengan jumlah elemen yang sama dengan jumlah elemen atau jumlah indeks yang Anda lewati ke dalam braket tunggal.
Sebaliknya, braket ganda akan selalu mengembalikan hanya satu elemen. Sebelum pindah ke bracket ganda, perlu diingat.
NOTE:THE MAJOR DIFFERENCE BETWEEN THE TWO IS THAT SINGLE BRACKET RETURNS YOU A LIST WITH AS MANY ELEMENTS AS YOU WISH WHILE A DOUBLE BRACKET WILL NEVER RETURN A LIST. RATHER A DOUBLE BRACKET WILL RETURN ONLY A SINGLE ELEMENT FROM THE LIST.
Saya akan memberikan beberapa contoh. Harap catat kata-kata dalam huruf tebal dan kembali lagi setelah Anda selesai dengan contoh-contoh di bawah ini:
Ganda braket akan kembali Anda nilai aktual di indeks. (Ini akan tidak kembali daftar)
> r[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
>r[["foo"]]
[1] 1
untuk kurung ganda jika kita mencoba melihat lebih dari satu elemen dengan melewatkan vektor, itu akan menghasilkan kesalahan hanya karena itu tidak dibangun untuk memenuhi kebutuhan itu, tetapi hanya untuk mengembalikan satu elemen.
Pertimbangkan yang berikut ini
> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds
[]
mengembalikan kelas daftar meskipun hanya satu digit sangat tidak intuitif. Mereka seharusnya membuat sintaks lain seperti ([])
untuk daftar dan [[]]
untuk mengakses elemen aktual baik-baik saja. Saya lebih suka menganggapnya [[]]
sebagai nilai mentah seperti dalam bahasa lain.
Untuk membantu pemula menavigasi kabut manual, mungkin bermanfaat untuk melihat [[ ... ]]
notasi sebagai fungsi runtuh - dengan kata lain, itu adalah saat Anda hanya ingin 'mendapatkan data' dari vektor, daftar, atau bingkai data yang dinamai. Adalah baik untuk melakukan ini jika Anda ingin menggunakan data dari objek-objek ini untuk perhitungan. Contoh-contoh sederhana ini akan menggambarkan.
(x <- c(x=1, y=2)); x[1]; x[[1]]
(x <- list(x=1, y=2, z=3)); x[1]; x[[1]]
(x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]]
Jadi dari contoh ketiga:
> 2 * x[1]
x
1 2
> 2 * x[[1]]
[1] 2
iris[[1]]
mengembalikan vektor, sedangkan iris[1]
mengembalikan data.frame
Menjadi terminologis, [[
operator mengekstrak elemen dari daftar sedangkan [
operator mengambil bagian dari daftar.
Untuk case use konkret lain, gunakan tanda kurung ganda ketika Anda ingin memilih bingkai data yang dibuat oleh split()
fungsi. Jika Anda tidak tahu, split()
kelompokkan daftar / bingkai data menjadi himpunan bagian berdasarkan bidang kunci. Ini berguna jika ketika Anda ingin beroperasi pada banyak grup, plot, dll.
> class(data)
[1] "data.frame"
> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"
> class(dsplit['ID-1'])
[1] "list"
> class(dsplit[['ID-1']])
[1] "data.frame"
Silakan lihat penjelasan di bawah ini.
Saya telah menggunakan bingkai data Built-in di R, yang disebut mtcars.
> mtcars
mpg cyl disp hp drat wt ...
Mazda RX4 21.0 6 160 110 3.90 2.62 ...
Mazda RX4 Wag 21.0 6 160 110 3.90 2.88 ...
Datsun 710 22.8 4 108 93 3.85 2.32 ...
............
Baris atas tabel disebut header yang berisi nama kolom. Setiap garis horizontal sesudahnya menunjukkan baris data, yang dimulai dengan nama baris, dan kemudian diikuti oleh data aktual. Setiap anggota data dari suatu baris disebut sel.
Untuk mengambil data dalam sel, kita akan memasukkan koordinat baris dan kolomnya di operator braket persegi "[]". Dua koordinat dipisahkan oleh koma. Dengan kata lain, koordinat dimulai dengan posisi baris, kemudian diikuti oleh koma, dan berakhir dengan posisi kolom. Urutan itu penting.
Misalnya 1: - Ini adalah nilai sel dari baris pertama, kolom kedua mtcars.
> mtcars[1, 2]
[1] 6
Misalnya 2: - Selanjutnya, kita dapat menggunakan nama baris dan kolom alih-alih koordinat numerik.
> mtcars["Mazda RX4", "cyl"]
[1] 6
Kami mereferensikan kolom bingkai data dengan operator braket kuadrat ganda "[[]]".
Misalnya 1: - Untuk mengambil vektor kolom kesembilan dari mtcars kumpulan data bawaan, kami menulis mtcars [[9]].
mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...
Misal 2: - Kita dapat mengambil vektor kolom yang sama dengan namanya.
mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...