Dalam jawaban untuk pertanyaan lain, @Marek memposting solusi berikut: https://stackoverflow.com/a/10432263/636656
dat <- structure(list(product = c(11L, 11L, 9L, 9L, 6L, 1L, 11L, 5L,
7L, 11L, 5L, 11L, 4L, 3L, 10L, 7L, 10L, 5L, 9L, 8L)), .Names = "product", row.names = c(NA, -20L), class = "data.frame")
`levels<-`(
factor(dat$product),
list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
)
Yang menghasilkan sebagai keluaran:
[1] Generic Generic Bayer Bayer Advil Tylenol Generic Advil Bayer Generic Advil Generic Advil Tylenol
[15] Generic Bayer Generic Advil Bayer Bayer
Ini hanyalah cetakan dari sebuah vektor, jadi untuk menyimpannya Anda dapat melakukan yang lebih membingungkan:
res <- `levels<-`(
factor(dat$product),
list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
)
Jelas ini adalah semacam panggilan ke fungsi level, tapi saya tidak tahu apa yang dilakukan di sini. Apa istilah untuk sihir jenis ini, dan bagaimana cara meningkatkan kemampuan sihir saya di domain ini?
names<-
dan[<-
.structure(...)
konstruksi daripada hanyadata.frame(product = c(11L, 11L, ..., 8L))
? (Jika ada keajaiban terjadi di sana, saya ingin menggunakannya juga!)"levels<-"
fungsifunction (x, value) .Primitive("levels<-")
:, semacam sukaX %in% Y
adalah singkatan dari"%in%"(X, Y)
.Jawaban:
Jawabannya di sini bagus, tetapi mereka melewatkan satu poin penting. Izinkan saya mencoba menjelaskannya.
R adalah bahasa fungsional dan tidak suka mengubah objeknya. Tapi itu memungkinkan pernyataan penugasan, menggunakan fungsi pengganti:
setara dengan
Triknya adalah, penulisan ulang ini dilakukan dengan
<-
; itu tidak dilakukan olehlevels<-
.levels<-
hanyalah fungsi biasa yang mengambil masukan dan memberikan keluaran; itu tidak mengubah apapun.Salah satu konsekuensinya adalah, menurut aturan di atas,
<-
harus rekursif:adalah
adalah
Agak indah bahwa transformasi fungsional murni ini (hingga akhir, di mana penugasan terjadi) setara dengan apa yang akan dilakukan penugasan dalam bahasa imperatif. Jika saya ingat dengan benar konstruksi ini dalam bahasa fungsional disebut lensa.
Tetapi kemudian, setelah Anda menentukan fungsi pengganti seperti
levels<-
, Anda mendapatkan rejeki nomplok lain yang tidak terduga: Anda tidak hanya memiliki kemampuan untuk membuat tugas, Anda memiliki fungsi praktis yang memperhitungkan faktor, dan memberikan faktor lain dengan level yang berbeda. Benar-benar tidak ada "tugas" tentang itu!Jadi, kode yang Anda gambarkan hanya memanfaatkan interpretasi lain ini
levels<-
. Saya akui bahwa namanyalevels<-
agak membingungkan karena menunjukkan suatu tugas, tetapi bukan ini yang terjadi. Kode tersebut hanya menyiapkan semacam pipeline:Dimulai dari
dat$product
Ubah menjadi faktor
Ubah levelnya
Simpan itu di
res
Secara pribadi, saya pikir baris kode itu indah;)
sumber
Tidak ada sihir, begitulah (sub) fungsi penugasan didefinisikan.
levels<-
sedikit berbeda karena primitif untuk (sub) menetapkan atribut faktor, bukan elemen itu sendiri. Ada banyak contoh dari jenis fungsi ini:Operator biner lain juga bisa disebut seperti itu:
Sekarang setelah Anda mengetahuinya, sesuatu seperti ini seharusnya benar-benar membuat Anda terkagum-kagum:
sumber
`levels<-`(foo,bar)
sama denganlevels(foo) <- bar
. Menggunakan contoh @ Marek:`levels<-`(as.factor(foo),bar)
sama denganfoo <- as.factor(foo); levels(foo) <- bar
.levels<-
itu benar-benar hanya singkatanattr<-(x, "levels") <- value
, atau setidaknya mungkin sampai itu berubah menjadi primitif dan diserahkan ke C-code.Alasan untuk "keajaiban" itu adalah bahwa formulir "tugas" harus memiliki variabel nyata untuk dikerjakan. Dan
factor(dat$product)
itu tidak ditugaskan untuk apa pun.sumber
within()
dantransform()
jika objek yang dimodifikasi demikian dikembalikan dan ditetapkan.Untuk kode pengguna, saya bertanya-tanya mengapa manipulasi bahasa seperti itu digunakan begitu? Anda bertanya sihir apa ini dan yang lain telah menunjukkan bahwa Anda memanggil fungsi pengganti yang memiliki nama itu
levels<-
. Bagi kebanyakan orang ini adalah sihir dan sebenarnya tujuan penggunaan adalahlevels(foo) <- bar
.Kasus penggunaan yang Anda tunjukkan berbeda karena
product
tidak ada di lingkungan global sehingga hanya pernah ada di lingkungan lokal panggilanlevels<-
sehingga perubahan yang ingin Anda buat tidak bertahan - tidak ada penugasan ulangdat
.Dalam keadaan ini,
within()
adalah fungsi yang ideal untuk digunakan. Anda tentu ingin menulisdi R tapi tentu saja
product
tidak ada sebagai objek.within()
mengatasi ini karena itu mengatur lingkungan yang Anda inginkan untuk menjalankan kode R Anda dan mengevaluasi ekspresi Anda dalam lingkungan itu. Menetapkan objek yang dikembalikan dari panggilan kewithin()
dengan demikian berhasil dalam bingkai data yang dimodifikasi dengan benar.Berikut ini contohnya (Anda tidak perlu membuat yang baru
datX
- saya hanya melakukannya agar langkah perantara tetap berada di akhir)Pemberian yang mana:
Saya kesulitan untuk melihat bagaimana konstruksi seperti yang Anda tunjukkan berguna dalam sebagian besar kasus - jika Anda ingin mengubah data, mengubah data, jangan membuat salinan lain dan mengubahnya (bagaimanapun juga semua
levels<-
panggilan itu lakukan ).sumber