R adalah bahasa yang berorientasi objek. Di dalamnya, semuanya adalah objek, mulai dari fungsi dan diakhiri dengan tabel.
Pada gilirannya, setiap objek di R milik kelas. Bahkan, di dunia sekitar kita, situasinya hampir sama. Kami dikelilingi oleh objek, dan setiap objek dapat dikaitkan dengan kelas. Kelas menentukan set properti dan tindakan yang dapat dilakukan dengan objek ini.

Misalnya, di dapur mana pun ada meja dan kompor. Dan meja dan kompor dapur bisa disebut peralatan dapur. Sifat-sifat tabel biasanya dibatasi oleh dimensi, warna, dan bahan dari mana tabel itu dibuat. Kompor memiliki sifat yang lebih luas, setidaknya daya, jumlah pembakar dan jenis kompor (listrik atau gas) akan menjadi wajib.
Tindakan yang dapat dilakukan pada objek disebut metode mereka. Untuk tabel dan plat, masing-masing, set metode juga akan berbeda. Anda bisa makan malam di meja, Anda bisa memasak di atasnya, tetapi tidak mungkin untuk memanaskan makanan, yang biasanya digunakan kompor.

Isi
Properti Kelas
Dalam R, setiap objek juga milik kelas. Tergantung pada kelasnya, ia memiliki serangkaian properti dan metode tertentu. Dalam hal pemrograman berorientasi objek (OOP), kemungkinan menggabungkan yang serupa dalam satu set properti dan metode objek ke dalam kelompok (kelas) disebut enkapsulasi .
Vektor adalah kelas objek yang paling sederhana dalam R, ia memiliki properti panjang. Sebagai contoh, kita akan mengambil huruf vektor bawaan .
length(letters)
[1] 26
Menggunakan fungsi length
, kami mendapat panjang vektor huruf . Sekarang mari kita coba menerapkan fungsi yang sama ke bingkai tanggal built-in iris .
length(iris)
[1] 5
Fungsi length
, berlaku untuk tabel, mengembalikan jumlah kolom.
Tabel juga memiliki properti lain, dimensi.
dim(iris)
[1] 150 5
Fungsi dim
pada contoh di atas menampilkan informasi bahwa ada 150 baris dan 5 kolom dalam tabel iris .
Pada gilirannya, vektor tidak memiliki dimensi.
dim(letters)
NULL
Jadi, kami memastikan bahwa objek dari kelas yang berbeda memiliki properti yang berbeda.
Fungsi Umum
R memiliki banyak fungsi generik: print
, plot
, summary
, dll. Fungsi-fungsi ini bekerja secara berbeda dengan objek dari kelas yang berbeda.
Ambil, misalnya, fungsi plot
. Mari kita jalankan dengan melewati tabel iris sebagai argumen utamanya.
plot(iris)
Hasil:

Sekarang mari kita coba meneruskan ke fungsi plot
vektor 100 angka acak yang memiliki distribusi normal.
plot(rnorm(100, 50, 30))
Hasil:

Kami mendapat grafik yang berbeda, dalam kasus pertama, matriks korelasi, di kedua, plot pencar, di mana indeks pengamatan ditampilkan di sepanjang sumbu x, dan nilainya di sepanjang sumbu y.
Dengan demikian, fungsi plot
dapat beradaptasi untuk bekerja dengan kelas yang berbeda. Jika kita kembali ke terminologi OOP, maka kemampuan untuk menentukan kelas dari objek yang masuk dan melakukan berbagai aksi dengan objek dari kelas yang berbeda disebut polimorfisme . Hal ini disebabkan oleh fakta bahwa fungsi ini hanyalah pembungkus untuk berbagai metode yang ditulis untuk bekerja dengan kelas yang berbeda. Anda dapat memverifikasi ini dengan perintah berikut:
body(plot)
UseMethod("plot")
Perintah body
mencetak body fungsi ke konsol R. Seperti yang Anda lihat, fungsi tubuh hanya terdiri dari satu UseMethod("plot")
.
Yaitu fungsi plot
, baru memulai salah satu dari banyak metode yang ditulis untuk itu, tergantung pada kelas objek yang diteruskan ke sana. Lihat daftar semua metodenya sebagai berikut.
methods(plot)
[1] plot.acf* plot.data.frame* plot.decomposed.ts* [4] plot.default plot.dendrogram* plot.density* [7] plot.ecdf plot.factor* plot.formula* [10] plot.function plot.hclust* plot.histogram* [13] plot.HoltWinters* plot.isoreg* plot.lm* [16] plot.medpolish* plot.mlm* plot.ppr* [19] plot.prcomp* plot.princomp* plot.profile.nls* [22] plot.raster* plot.spec* plot.stepfun [25] plot.stl* plot.table* plot.ts [28] plot.tskernel* plot.TukeyHSD*
Hasilnya menunjukkan bahwa fungsi plot memiliki 29 metode, di antaranya ada plot.default , yang berfungsi secara default jika fungsi menerima objek dari kelas yang tidak dikenal ke input.
Menggunakan fungsi methods
, Anda juga bisa mendapatkan satu set semua fungsi umum yang memiliki metode yang ditulis untuk kelas apa pun.
methods(, "data.frame")
[1] $<- [ [[ [[<- [5] [<- aggregate anyDuplicated as.data.frame [9] as.list as.matrix by cbind [13] coerce dim dimnames dimnames<- [17] droplevels duplicated edit format [21] formula head initialize is.na [25] Math merge na.exclude na.omit [29] Ops plot print prompt [33] rbind row.names row.names<- rowsum [37] show slotsFromS3 split split<- [41] stack str subset summary [45] Summary t tail transform [49] type.convert unique unstack within
Apa itu kelas S3 dan cara membuat kelas Anda sendiri
Ada sejumlah kelas dalam R yang bisa Anda buat sendiri. Salah satu yang paling populer adalah S3.
Kelas ini adalah daftar di mana berbagai properti dari kelas yang Anda buat disimpan. Untuk membuat kelas Anda sendiri, cukup buat daftar dan berikan nama kelas.
Buku "Seni Pemrograman dalam R" memberikan contoh kelas karyawan , yang menyimpan informasi tentang karyawan. Sebagai contoh untuk artikel ini, saya juga memutuskan untuk mengambil objek untuk menyimpan informasi tentang karyawan. Tetapi membuatnya lebih kompleks dan fungsional.
# employee1 <- list(name = "Oleg", surname = "Petrov", salary = 1500, salary_datetime = Sys.Date(), previous_sallary = NULL, update = Sys.time()) # class(employee1) <- "emp"
Jadi, kami menciptakan kelas kami sendiri, yang menyimpan data berikut dalam strukturnya:
- Nama Karyawan
- Nama keluarga karyawan
- Gaji
- Waktu ketika gaji ditetapkan
- Gaji sebelumnya
- Tanggal dan waktu pembaruan terakhir informasi
Setelah itu, dengan perintah class(employee1) <- "emp"
kita menetapkan class emp ke objek.
Untuk kenyamanan membuat objek kelas emp, Anda bisa menulis fungsi.
Kode fungsi untuk membuat objek kelas emp # create_employee <- function(name, surname, salary, salary_datetime = Sys.Date(), update = Sys.time()) { out <- list(name = name, surname = surname, salary = salary, salary_datetime = salary_datetime, previous_sallary = NULL, update = update) class(out) <- "emp" return(out) } # emp create_employee employee1 <- create_employee("Oleg", "Petrov", 1500) # class(employee1)
[1] "emp"
Fungsi Penugasan untuk Kelas S3 Kustom
Jadi, kami membuat emp kelas kami sendiri, tetapi sejauh ini tidak memberi kami apa-apa. Mari kita lihat mengapa kita menciptakan kelas kita sendiri dan apa yang dapat kita lakukan dengannya.
Pertama-tama, Anda bisa menulis fungsi tugas untuk kelas yang dibuat.
Fungsi Penugasan untuk [ "[<-.emp" <- function(x, i, value) { if ( i == "salary" || i == 3 ) { cat(x$name, x$surname, "has changed salary from", x$salary, "to", value) x$previous_sallary <- x$salary x$salary <- value x$salary_datetime <- Sys.Date() x$update <- Sys.time() } else { cat( "You can`t change anything except salary" ) } return(x) }
Fungsi Penugasan untuk [[ "[[<-.emp" <- function(x, i, value) { if ( i == "salary" || i == 3 ) { cat(x$name, x$surname, "has changed salary from", x$salary, "to", value) x$previous_sallary <- x$salary x$salary <- value x$salary_datetime <- Sys.Date() x$update <- Sys.time() } else { cat( "You can`t change anything except salary" ) } return(x) }
Saat membuat, fungsi penugasan selalu dikutip, dan terlihat seperti ini: "[<-. " / "[[<-. "
. Dan mereka memiliki 3 argumen yang diperlukan.
- x - Objek tempat nilai akan diberikan;
- i - Nama / indeks elemen objek (nama, nama keluarga, gaji, gaji_datetime, prior_sallary, pembaruan);
- value - Nilai yang diberikan.
Lebih jauh dalam tubuh fungsi Anda menulis bagaimana elemen-elemen kelas Anda harus berubah. Dalam kasus saya, saya ingin pengguna hanya dapat mengubah gaji (elemen gaji , yang indeksnya 3) . Oleh karena itu, di dalam fungsi, saya menulis cek if ( i == "salary" || i == 3 )
. Jika pengguna mencoba mengedit properti lain, ia menerima pesan "You can't change anything except salary"
.
Ketika elemen gaji diubah, sebuah pesan ditampilkan berisi nama dan nama keluarga karyawan, tingkat gajinya saat ini dan yang baru. Gaji saat ini diteruskan ke properti before_sallary, dan gaji diberi nilai baru. Nilai-nilai dari income_datetime dan pembaruan properti juga diperbarui.
Sekarang Anda dapat mencoba mengubah gaji.
employee1["salary"] <- 1750
Oleg Petrov has changed salary from 1500 to 1750
Mengembangkan metode khusus untuk fungsi umum
Sebelumnya, Anda sudah belajar bahwa di R ada fungsi umum yang mengubah perilaku mereka tergantung pada kelas yang diterima pada input objek.
Anda dapat menambahkan metode Anda ke fungsi umum yang ada dan bahkan membuat fungsi umum Anda sendiri.
Salah satu fungsi generik yang paling umum digunakan adalah print
. Fungsi ini dipicu setiap kali Anda memanggil objek dengan namanya. Sekarang hasil cetak objek kelas emp yang kita buat terlihat seperti ini:
$name [1] "Oleg" $surname [1] "Petrov" $salary [1] 1750 $salary_datetime [1] "2019-05-29" $previous_sallary [1] 1500 $update [1] "2019-05-29 11:13:25 EEST"
Mari kita menulis metode kita untuk fungsi cetak.
print.emp <- function(x) { cat("Name:", x$name, x$surname, "\n", "Current salary:", x$salary, "\n", "Days from last udpate:", Sys.Date() - x$salary_datetime, "\n", "Previous salary:", x$previous_sallary) }
Sekarang fungsi cetak dapat mencetak objek dari kelas emp kami. Cukup masukkan nama objek di konsol dan dapatkan output berikut.
employee1
Name: Oleg Petrov Current salary: 1750 Days from last udpate: 0 Previous salary: 1500
Membuat fungsi dan metode umum
Sebagian besar fungsi generik di dalamnya terlihat sama dan hanya menggunakan fungsi UseMethod
.
# get_salary <- function(x, ...) { UseMethod("get_salary") }
Sekarang kita akan menulis dua metode untuk itu, satu untuk bekerja dengan objek dari kelas emp , metode kedua akan diluncurkan secara default untuk objek dari semua kelas lain, untuk bekerja dengan mana fungsi umum kita tidak memiliki metode yang ditulis secara terpisah.
# emp get_salary.emp <- function(x) x$salary # get_salary.default <- function(x) cat("Work only with emp class objects")
Nama metode terdiri dari nama fungsi dan kelas objek yang akan diproses metode ini. Metode default akan dijalankan setiap kali jika Anda melewatkan objek kelas yang metode ini tidak ditulis.
get_salary(employee1)
[1] 1750
get_salary(iris)
Work only with emp class objects
Warisan
Istilah lain yang akan Anda temui ketika belajar pemrograman berorientasi objek.

Segala sesuatu yang ditunjukkan dalam gambar dapat diklasifikasikan sebagai kelas transportasi . Memang, semua benda ini memiliki metode umum - gerakan, dan properti umum, misalnya, kecepatan. Namun demikian, semua 6 objek dapat dibagi menjadi tiga subclass: tanah, air dan udara. Dalam hal ini, subclass akan mewarisi properti dari kelas induk, tetapi juga akan memiliki properti dan metode tambahan. Properti serupa dalam kerangka pemrograman berorientasi objek disebut pewarisan .
Dalam contoh kami, kami dapat mengalokasikan pekerja jarak jauh ke subkelas terpisah dari remote_emp . Karyawan tersebut akan memiliki properti tambahan: kota tempat tinggal.
# employee2 <- list(name = "Ivan", surname = "Ivanov", salary = 500, salary_datetime = Sys.Date(), previous_sallary = NULL, update = Sys.time(), city = "Moscow") # remote_emp class(employee2) <- c("remote_emp", "emp") # class(employee2)
[1] "remote_emp" "emp"
Saat menetapkan kelas, membuat subkelas, kami menggunakan vektor di mana elemen pertama adalah nama subkelas, diikuti dengan nama kelas induk.
Dalam hal pewarisan, semua fungsi umum dan metode yang ditulis untuk bekerja dengan kelas induk akan bekerja dengan benar dengan subkelasnya.
# remote_emp employee2
Name: Ivan Ivanov Current salary: 500 Days from last udpate: 0 Previous salary:
# salary remote_emp get_salary(employee2)
[1] 500
Tetapi Anda dapat mengembangkan metode secara terpisah untuk setiap subkelas.
# salary remote_emp get_salary.remote_emp <- function(x) { cat(x$surname, "remote from", x$city, "\n") return(x$salary) }
# salary remote_emp get_salary(employee2)
Ivanov remote from Moscow [1] 500
Ini berfungsi sebagai berikut. Pertama, fungsi umum mencari metode yang ditulis untuk subclass remote_emp , jika tidak menemukannya, ia melangkah lebih jauh dan mencari metode yang ditulis untuk emp kelas induk.
Kapan Anda bisa menggunakan kelas Anda sendiri
Tidak mungkin bahwa fungsi membuat kelas S3 Anda sendiri akan bermanfaat bagi mereka yang baru memulai perjalanan mereka dalam menguasai bahasa R.
Secara pribadi, mereka sangat berguna dalam mengembangkan paket rfacebookstat . Faktanya adalah bahwa di Facebook API, parameter action_breakdowns ada untuk memuat acara dan menanggapi publikasi iklan dalam berbagai grup.
Saat menggunakan pengelompokan seperti itu, Anda mendapatkan respons dalam bentuk struktur JSON dalam format berikut:
{ "action_name": "like", "action_type": "post_reaction", "value": 6 } { "action_type": "comment", "value": 4 }
Jumlah dan nama elemen untuk action_breakdowns berbeda berbeda, jadi untuk masing-masing Anda perlu menulis parser Anda sendiri. Untuk mengatasi masalah ini, saya menggunakan fungsionalitas untuk membuat kelas S3 kustom dan fungsi umum dengan seperangkat metode.
Saat meminta statistik acara dengan pengelompokan, tergantung pada nilai argumen, kelas didefinisikan yang ditugaskan untuk respons yang diterima dari API. Respons diteruskan ke fungsi generik, dan tergantung pada kelas yang ditentukan sebelumnya, metode ditentukan yang mem-parsing hasilnya. Siapa pun yang tertarik mempelajari detail implementasi dapat menemukan kode untuk membuat fungsi dan metode umum, dan inilah penggunaannya.
Dalam kasus saya, saya menggunakan kelas dan metode untuk memprosesnya secara eksklusif di dalam paket. Jika Anda perlu secara umum menyediakan pengguna paket dengan antarmuka untuk bekerja dengan kelas yang Anda buat, maka semua metode harus dimasukkan sebagai direktif S3method
dalam file S3method
, sebagai berikut.
S3method(_,) S3method("[<-",emp) S3method("[[<-",emp) S3method("print",emp)
Kesimpulan
Seperti yang jelas dari judul artikel, ini hanya bagian pertama, karena di R, selain kelas S3 , ada yang lain: S4 , R5 ( RC ), R6 . Di masa depan saya akan mencoba menulis tentang masing-masing implementasi OOP ini. Namun demikian, siapa pun dengan tingkat bahasa Inggris yang memungkinkan mereka membaca buku dengan bebas, maka Headley Wickham cukup ringkas, dan dengan contoh-contoh meliput topik ini dalam bukunya "Advanced R" .
Jika tiba-tiba dalam artikel saya melewatkan beberapa informasi penting tentang kelas S3, saya akan berterima kasih jika Anda menulis tentang ini di komentar.