base VS dplyrPada postingan kali kita akan membahas mengenai manajemen Data Frame: Munging Data dengan membandingkan langkah-langkah menggunakan syntax base dan syntax dari library dplyr dan tidyr (tidyverse)
library(tidyverse)
Library tidyverse merupakan library yang terdiri dari kumpulan beberapa library didalamnya. Perhatikan gambar di bawah ini:
tidyverse, Source: https://www.analyticsvidhya.com/blog/2019/05/beginner-guide-tidyverse-most-powerful-collection-r-packages-data-science/
Gambar di atas merupakan kumpulan library yang berada di dalam library tidyverse. Kali ini kita hanya akan menggunakan 2 library dalam tidyverse yaitu dplyr dan tidyr
Data yang digunakan adalah data Orange yang tersedia di dalam R
head(Orange)
## Tree age circumference
## 1 1 118 30
## 2 1 484 58
## 3 1 664 87
## 4 1 1004 115
## 5 1 1231 120
## 6 1 1372 142
nb: Function head menampilkan baris teratas sebanyak 6 (by default), sedangkan function tail menampilkan baris terbawah sebanyak 6 (by default)
str(Orange)
## Classes 'nfnGroupedData', 'nfGroupedData', 'groupedData' and 'data.frame': 35 obs. of 3 variables:
## $ Tree : Ord.factor w/ 5 levels "3"<"1"<"5"<"2"<..: 2 2 2 2 2 2 2 4 4 4 ...
## $ age : num 118 484 664 1004 1231 ...
## $ circumference: num 30 58 87 115 120 142 145 33 69 111 ...
## - attr(*, "formula")=Class 'formula' language circumference ~ age | Tree
## .. ..- attr(*, ".Environment")=<environment: R_EmptyEnv>
## - attr(*, "labels")=List of 2
## ..$ x: chr "Time since December 31, 1968"
## ..$ y: chr "Trunk circumference"
## - attr(*, "units")=List of 2
## ..$ x: chr "(days)"
## ..$ y: chr "(mm)"
Data Orange merupakan data yang berisi mengenai pohon jeruk, menampilkan 3 variabel dan 35 observasi, 3 variabel diantaranya:
Orange$Tree
## [1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 5 5 5 5 5 5 5
## Levels: 3 < 1 < 5 < 2 < 4
Age: vector numerik, yang menunjukkan umur pohon jeruk (dalam satuan hari)
Circumference: vector numerik, yang menunjukkan diameter batang pohon jeruk (mm)
Orange$Var_baru <- 1:35
head(Orange,3)
## Tree age circumference Var_baru
## 1 1 118 30 1
## 2 1 484 58 2
## 3 1 664 87 3
Orange[,"Var_baru"] <- 1:35
head(Orange, 3)
## Tree age circumference Var_baru
## 1 1 118 30 1
## 2 1 484 58 2
## 3 1 664 87 3
Orange <- Orange[,1:3]
mutate()Orange %>%
mutate(Var_baru=1:35) %>%
head(3)
## Tree age circumference Var_baru
## 1 1 118 30 1
## 2 1 484 58 2
## 3 1 664 87 3
SUbset data digunakan untuk mengakses sebagian data.
Mencoba mengambil sebagian data dari Orange yang hanya Tree 1
Orange[Orange$Tree == 1,]
## Tree age circumference
## 1 1 118 30
## 2 1 484 58
## 3 1 664 87
## 4 1 1004 115
## 5 1 1231 120
## 6 1 1372 142
## 7 1 1582 145
filter() untuk memilih sebagian data berdasarkan nilai tertentuOrange %>%
filter(Tree==1)
## Tree age circumference
## 1 1 118 30
## 2 1 484 58
## 3 1 664 87
## 4 1 1004 115
## 5 1 1231 120
## 6 1 1372 142
## 7 1 1582 145
Hanya mengambil kolom Tree dan Age
head(Orange[,c(1,2)],3)
## Tree age
## 1 1 118
## 2 1 484
## 3 1 664
head(Orange[,c("Tree","age")],3)
## Tree age
## 1 1 118
## 2 1 484
## 3 1 664
select() untuk memilih sebagian data berdasarkan peubah tertentuOrange %>%
select(c(1,2)) %>%
head(3)
## Tree age
## 1 1 118
## 2 1 484
## 3 1 664
Orange[Orange$Tree == 2 |Orange$age>1500,]
## Tree age circumference
## 7 1 1582 145
## 8 2 118 33
## 9 2 484 69
## 10 2 664 111
## 11 2 1004 156
## 12 2 1231 172
## 13 2 1372 203
## 14 2 1582 203
## 21 3 1582 140
## 28 4 1582 214
## 35 5 1582 177
dplyr::filter() untuk mengambil data Orange yang mempunyai nilai Tree=2 (atau) Age>1500Orange %>%
filter(Tree == 2|age>1500)
## Tree age circumference
## 1 1 1582 145
## 2 2 118 33
## 3 2 484 69
## 4 2 664 111
## 5 2 1004 156
## 6 2 1231 172
## 7 2 1372 203
## 8 2 1582 203
## 9 3 1582 140
## 10 4 1582 214
## 11 5 1582 177
Orange[Orange$Tree==1 & Orange$age > 1500,]
## Tree age circumference
## 7 1 1582 145
dplyr::filter() untuk mengambil Orange yang termasuk kelompok 2 (dan) perlakuan P3Orange %>%
filter(Tree == 2&age>1500)
## Tree age circumference
## 1 2 1582 203
idx <- Orange$circumference %in% c(203,204,214)
Orange[idx,]
## Tree age circumference
## 13 2 1372 203
## 14 2 1582 203
## 28 4 1582 214
Orange %>%
filter(circumference %in% c(203, 204, 214))
## Tree age circumference
## 1 2 1372 203
## 2 2 1582 203
## 3 4 1582 214
Sorting data berfungsi untuk mengurutkan data sesuai dengan variabel tertentu dalam data frame.
head(Orange[order(Orange$age),])
## Tree age circumference
## 1 1 118 30
## 8 2 118 33
## 15 3 118 30
## 22 4 118 32
## 29 5 118 30
## 2 1 484 58
dplyr::arrange()Orange %>%
arrange(age) %>%
head()
## Tree age circumference
## 1 1 118 30
## 2 2 118 33
## 3 3 118 30
## 4 4 118 32
## 5 5 118 30
## 6 1 484 58
head(Orange[order(Orange$circumference, decreasing = T),])
## Tree age circumference
## 28 4 1582 214
## 27 4 1372 209
## 13 2 1372 203
## 14 2 1582 203
## 26 4 1231 179
## 35 5 1582 177
dplyr::arrange()Orange %>%
arrange(desc(circumference)) %>%
head()
## Tree age circumference
## 1 4 1582 214
## 2 4 1372 209
## 3 2 1372 203
## 4 2 1582 203
## 5 4 1231 179
## 6 5 1582 177
idx1 <- order(Orange$circumference,decreasing=TRUE)
Orange2 <- Orange[idx1,]
idx2 <- order(Orange2$age)
Orange3 <- Orange2[idx2,]
head(Orange3)
## Tree age circumference
## 8 2 118 33
## 22 4 118 32
## 1 1 118 30
## 15 3 118 30
## 29 5 118 30
## 9 2 484 69
df_orange <- Orange %>%
arrange(desc(circumference))
df_orange %>%
arrange(age) %>%
head()
## Tree age circumference
## 1 2 118 33
## 2 4 118 32
## 3 1 118 30
## 4 3 118 30
## 5 5 118 30
## 6 2 484 69
nb) lakukan langkah descending terlebih dahulu, lak=lu diikuti dengan ascending
order, sort, rev, rank, dan whichPerhatikan data variabel age dari data Orange berikut:
Orange$age
## [1] 118 484 664 1004 1231 1372 1582 118 484 664 1004 1231 1372 1582 118
## [16] 484 664 1004 1231 1372 1582 118 484 664 1004 1231 1372 1582 118 484
## [31] 664 1004 1231 1372 1582
order, R akan mengeluarkan nomor index data Tree dari yang terkecil hingga terbesar (jika ascending)order(Orange$age)
## [1] 1 8 15 22 29 2 9 16 23 30 3 10 17 24 31 4 11 18 25 32 5 12 19 26 33
## [26] 6 13 20 27 34 7 14 21 28 35
sort, R akan mengeluarkan nilai sesungguhnya data Tree dari yang terkecil hingga terbesar (jika ascending)sort(Orange$age)
## [1] 118 118 118 118 118 484 484 484 484 484 664 664 664 664 664
## [16] 1004 1004 1004 1004 1004 1231 1231 1231 1231 1231 1372 1372 1372 1372 1372
## [31] 1582 1582 1582 1582 1582
rev, nilai apa yang dikeluarkan oleh R?rev(Orange$age)
## [1] 1582 1372 1231 1004 664 484 118 1582 1372 1231 1004 664 484 118 1582
## [16] 1372 1231 1004 664 484 118 1582 1372 1231 1004 664 484 118 1582 1372
## [31] 1231 1004 664 484 118
Ternyata funtion rev() tidak mengeluarkan nilai ascending atau descending, lalu nilai apa itu?
Funtion rev() berguna jika kita membuat data menggunakan dendogram.
Dendogram merupakan representasi visual dari cluster data yang bersifat hierarki.
Function rev() akan mengeluarkan nilai sesungguhnya dari dendogram.
Perhatikan dendogram berikut:
# Jarak Euclidean
dist <- dist(Orange[ ,"age"])
# Hierarchical Clustering dengan function hclust
hc <- hclust(dist)
# Plot the result
plot(hc)
Nilai yang dikeluarkan oleh dendogram diatas adalah nilai index dari data
Orange$age yang telah dikelompokkan secara hierarki. Sekarang kita akan coba mengeluardan nilai index dari rev(Orange$age)
order(rev(Orange$age))
## [1] 7 14 21 28 35 6 13 20 27 34 5 12 19 26 33 4 11 18 25 32 3 10 17 24 31
## [26] 2 9 16 23 30 1 8 15 22 29
Dari output di atas dapat dilihat jika kita ingin mengelompokkan nilai-nilai age menjadi 7 kelompok, maka kelompok 1 akan diisi oleh nilai-nilai age dengan index dari 7 hingga 35, kelompok 2 akan diisi oleh nilai dengan index 6 hingga 34, dan seterusnya.
Untuk melihat apa yang dijalankan function rank() akan mudah dibayangkan jika menggunakan data sederhana berikut:
x1 <- c(30, 10, 55, 75, 92)
rank(x1)
## [1] 2 1 3 4 5
Rank akan mengeluarkan nomor index dari data terkecil hingga terbesar.
x2 <- c(20, 10, 20, 50, 50, 50, 15)
#Untuk memudahkan melihat perubahan tambahkan nama index
names(x2) <- letters[1:7]
x2
## a b c d e f g
## 20 10 20 50 50 50 15
#Jika nilai sesungguhnya diurutkan
sort(x2)
## b g a c d e f
## 10 15 20 20 50 50 50
rank(x2)
## a b c d e f g
## 3.5 1.0 3.5 6.0 6.0 6.0 2.0
Perhatikan nilai outpun rank di atas, index a dan c besarnya 3.5 didapatkan dari urutan index a dan c adalah urutan ke 3 dan 4, \((3+4)/2=3.5\). Jadi nilai 3.5 merupakan nilai rata-rata index setelah data diurutkan. Sehingga function rank() berfungsi untuk mengeluarkan nilai rata-rata index setelah data diurutkan.
which() akan mengeluarkan nilai index dari data dengan kondisi yang disyaratkanwhich(Orange$age>1500)
## [1] 7 14 21 28 35
#Mengeluarkan nilai sesungguhnya dari index yang dikeluarkan oleh function which
Orange$age[Orange$age>1500]
## [1] 1582 1582 1582 1582 1582
Orange$age[which(Orange$age>1500)]
## [1] 1582 1582 1582 1582 1582
Recoding Data berfungsi untuk membuat nilai baru dari nilai variabel yang sudah ada
Misalkan akan dilakukan recoding pada data Orange untuk variabel age dengan kondisi jika \(age<=1000\) maka Code = 0, selainnya Code = 1
Recoding Data dengan syntax base
Menggunakan base dengan logika
0*(Orange$age<=1000) + 1*(Orange$age>1000)
## [1] 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1
ifelse()ifelse(Orange$age<=1000,0,1)
## [1] 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1
car::recode()library(car)
## Loading required package: carData
##
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
##
## recode
## The following object is masked from 'package:purrr':
##
## some
recode(Orange$age,'1:1000=0; else=1')
## [1] 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1
dplyr::mutate()Orange %>%
mutate(code_age=ifelse(age>1000,1,0)) %>%
head()
## Tree age circumference code_age
## 1 1 118 30 0
## 2 1 484 58 0
## 3 1 664 87 0
## 4 1 1004 115 1
## 5 1 1231 120 1
## 6 1 1372 142 1
Merging data berfungsi untuk menggabungkan data berdasarkan key variable (Variabel kunci)
pohon <- factor(c(3,1,4), levels = c(3,1,5,2,4), ordered=T)
rasa <- c("asem", "manis", "pahit")
(df_1 <- data.frame(pohon, rasa))
## pohon rasa
## 1 3 asem
## 2 1 manis
## 3 4 pahit
Misalkan akan digabungkan data frame Orange dengan df_1 berdasarkan variabel ‘Tree’ dan ‘pohon’
merge()#Dengan parameter all=F
data1 <- merge(Orange, df_1, by.x="Tree", by.y="pohon", all=FALSE)
head(data1)
## Tree age circumference rasa
## 1 1 664 87 manis
## 2 1 1004 115 manis
## 3 1 118 30 manis
## 4 1 484 58 manis
## 5 1 1582 145 manis
## 6 1 1231 120 manis
str(data1)
## 'data.frame': 21 obs. of 4 variables:
## $ Tree : Ord.factor w/ 5 levels "3"<"1"<"5"<"2"<..: 2 2 2 2 2 2 2 1 1 1 ...
## $ age : num 664 1004 118 484 1582 ...
## $ circumference: num 87 115 30 58 145 120 142 51 30 139 ...
## $ rasa : chr "manis" "manis" "manis" "manis" ...
Jika parameter all=FALSE maka R akan membuang baris yang tidak memiliki nilai dikedua variabel kunci yaitu variabel tree pada data Orange dan variabe pohon pada df_1 (variabel-variabel yang akan digabungkan menjadi 1 kolom saja). Pada variabel pohon dalam df_1 hanya memiliki pohon dengan nomor 3, 1, dan 4. Sehingga R akan membuang baris yang dimana variabel Orange$Tree bernilai selain 3, 1, dan 4. Itulah mengapa jumlah observasi data1 hanya sebanyak 21 observasi.
data1$Tree
## [1] 1 1 1 1 1 1 1 3 3 3 3 3 3 3 4 4 4 4 4 4 4
## Levels: 3 < 1 < 5 < 2 < 4
#Jika parameter all=T
data2 <- merge(Orange, df_1, by.x=1, by.y=1, all=T)
data2$Tree
## [1] 3 3 3 3 3 3 3 1 1 1 1 1 1 1 5 5 5 5 5 5 5 2 2 2 2 2 2 2 4 4 4 4 4 4 4
## Levels: 3 < 1 < 5 < 2 < 4
str(data2)
## 'data.frame': 35 obs. of 4 variables:
## $ Tree : Ord.factor w/ 5 levels "3"<"1"<"5"<"2"<..: 1 1 1 1 1 1 1 2 2 2 ...
## $ age : num 484 118 1372 664 1004 ...
## $ circumference: num 51 30 139 75 108 115 140 87 115 30 ...
## $ rasa : chr "asem" "asem" "asem" "asem" ...
Jika parameter all=TRUE maka R tidak akan membuang baris walaupun baris tersebut hanya dimiliki oleh salah satu variabel kunci. Itulah mengapa jumlah observasi data2 tetap sebanyak 35 observasi. Namun R akan mengisi nilai variabel ‘rasa’ yang dimana jika variabel ‘Tree’ bernilai selain 3, 1, dan 4 menjadi NA.
data2[is.na(data2$rasa),]
## Tree age circumference rasa
## 15 5 664 81 <NA>
## 16 5 118 30 <NA>
## 17 5 484 49 <NA>
## 18 5 1582 177 <NA>
## 19 5 1004 125 <NA>
## 20 5 1231 142 <NA>
## 21 5 1372 174 <NA>
## 22 2 484 69 <NA>
## 23 2 664 111 <NA>
## 24 2 1004 156 <NA>
## 25 2 118 33 <NA>
## 26 2 1372 203 <NA>
## 27 2 1582 203 <NA>
## 28 2 1231 172 <NA>
dplyr::inner_join()Function dplyr::inner_join() merupakan alternatif lain dari function merge() jika parameter all=F
data_3 <- dplyr::inner_join(Orange, df_1,
by = c("Tree" = "pohon"))
str(data_3)
## Classes 'nfnGroupedData', 'nfGroupedData', 'groupedData' and 'data.frame': 21 obs. of 4 variables:
## $ Tree : Ord.factor w/ 5 levels "3"<"1"<"5"<"2"<..: 2 2 2 2 2 2 2 1 1 1 ...
## $ age : num 118 484 664 1004 1231 ...
## $ circumference: num 30 58 87 115 120 142 145 30 51 75 ...
## $ rasa : chr "manis" "manis" "manis" "manis" ...
dplyr::left_join()Function dplyr::left_join() merupakan alternatif lain dari function merge() jika parameter all=T
data_4 <- dplyr::left_join(Orange, df_1,
by = c("Tree" = "pohon"))
str(data_4)
## Classes 'nfnGroupedData', 'nfGroupedData', 'groupedData' and 'data.frame': 35 obs. of 4 variables:
## $ Tree : Ord.factor w/ 5 levels "3"<"1"<"5"<"2"<..: 2 2 2 2 2 2 2 4 4 4 ...
## $ age : num 118 484 664 1004 1231 ...
## $ circumference: num 30 58 87 115 120 142 145 33 69 111 ...
## $ rasa : chr "manis" "manis" "manis" "manis" ...
Perlu diperhatikan jika menggunakan function dari dplyr key variables harus memiliki tipe data yang sama, selain inner_join dan left_join tentunya library dplyr memiliki function yang lainya untuk melakukan merging data dengan kondisi yang berbeda, jika anda ingin mempelajari function lainnya yang ada di dalam library dplyr dapat melihat cheatsheet berikut: https://4.files.edl.io/b9e2/07/12/19/142839-a23788fb-1d3a-4665-9dc4-33bfd442c296.pdf
Reshaping Data berfungsi untuk mengubah bentuk data frame menjadi:
• Long to wide format
• Wide to long format
Untuk mempermudah memahami maka kita akan gunakan data bangkitan yang lebih simpel, seperti berikut:
jenis_kelamin <- factor(c("M", "M", "M", "F","F", "F"))
kelas <- factor(c("a","b","c","a","b","c"))
bb <- c(60, 55, 65, 601, 52 ,48)
df_2 <- data.frame(kelas,jenis_kelamin, bb)
df_2
## kelas jenis_kelamin bb
## 1 a M 60
## 2 b M 55
## 3 c M 65
## 4 a F 601
## 5 b F 52
## 6 c F 48
reshape()(data_wide <- reshape(df_2, idvar="jenis_kelamin", timevar="kelas", direction="wide"))
## jenis_kelamin bb.a bb.b bb.c
## 1 M 60 55 65
## 4 F 601 52 48
Dapat dilihat perbedaan yang tadinya data terdiri dari 6 observasi dan 3 kolom, berubah menjadi wide format atau sering dikenal dengan istilah tabel kontingensi, dimana data_wide merupakan tabel kontingensi dengan ukuran 2x3.
reshape(data_wide, idvar="jenis_kelamin", timevar="kelas", direction="long")
## jenis_kelamin kelas bb.a
## M.a M a 60
## F.a F a 601
## M.b M b 55
## F.b F b 52
## M.c M c 65
## F.c F c 48
Dapat dilihat data yang tadinya berbentuk tabel kontingensi 2x3 kembali berubah menjadi tabel df_2.
tidyr::spread()wide2 <- df_2%>% spread(kelas, bb)
wide2
## jenis_kelamin a b c
## 1 F 601 52 48
## 2 M 60 55 65
tidyr::gather()wide2 %>% gather(kelas,bb, a:c)
## jenis_kelamin kelas bb
## 1 F a 601
## 2 M a 60
## 3 F b 52
## 4 M b 55
## 5 F c 48
## 6 M c 65
Modul Praktikum Pemrograman Statistika Tahun 2020 mengenai Manajemen Data Frame
(Program Magister Statistika dan Sains Data Departemen Statistika FMIPA-IPB University)
Feel free to discuss: