Pada 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:

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

1 Data

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:

  • Tree: vector factor ordered, menunjukkan kode tempat pohon penelitian, pengurutan sesuai dengan diameter maksimum yang bertambah.
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)

2 Membuat Peubah Baru

  • Membuat peubah baru dengan syntax base
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
  • Menghapus var_baru yang dibangkitkan
Orange <- Orange[,1:3]
  • Membuat peubah baru dengan dplyr dengan function 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

3 Subset Data

SUbset data digunakan untuk mengakses sebagian data.

Mencoba mengambil sebagian data dari Orange yang hanya Tree 1

  • Subset Data dengan syntax base untuk memilih sebagian data berdasarkan nilai tertentu
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
  • Subset Data dengan dplyr menggunakkan function filter() untuk memilih sebagian data berdasarkan nilai tertentu
Orange %>% 
  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
  • Subset Data dengan syntax base untuk memilih sebagian data berdasarkan peubah tertentu

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
  • Subset Data dengan dplyr menggunakkan function select() untuk memilih sebagian data berdasarkan peubah tertentu
Orange %>% 
  select(c(1,2)) %>% 
  head(3)
##   Tree age
## 1    1 118
## 2    1 484
## 3    1 664
  • Menggunakan syntax base untuk mengambil data Orange yang mempunyai nilai Tree=2 (atau) Age>1500
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
  • Menggunakan dplyr::filter() untuk mengambil data Orange yang mempunyai nilai Tree=2 (atau) Age>1500
Orange %>% 
  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
  • Menggunakan syntax base untuk mengambil Orange yang termasuk kelompok 2 (dan) perlakuan P3
Orange[Orange$Tree==1 & Orange$age > 1500,]
##   Tree  age circumference
## 7    1 1582           145
  • Menggunakan dplyr::filter() untuk mengambil Orange yang termasuk kelompok 2 (dan) perlakuan P3
Orange %>% 
  filter(Tree == 2&age>1500)
##   Tree  age circumference
## 1    2 1582           203
  • Menggunakan syntax base untuk mengambil amatan yang circumference = 203, 204, 214
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
  • Menggunakan dplyr untuk mengambil amatan yang circumference = 203, 204, 214
Orange %>% 
  filter(circumference %in% c(203, 204, 214))
##   Tree  age circumference
## 1    2 1372           203
## 2    2 1582           203
## 3    4 1582           214

4 Sorting Data

Sorting data berfungsi untuk mengurutkan data sesuai dengan variabel tertentu dalam data frame.

  • Mengurutkan Orange berdasarkan variabel Age secara ascending (dari umur pohon yang terkecil hingga terbesar) menggunakan syntax base
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
  • Mengurutkan Orange berdasarkan variabel Age secara ascending (dari umur pohon yang terkecil hingga terbesar) menggunakan 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
  • Mengurutkan Orange berdasarkan variabel circumference secara descending (dari ukuran diamerter pohon terbesar hingga terkecil) menggunakan syntax base
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
  • Mengurutkan Orange berdasarkan variabel circumference secara descending (dari ukuran diamerter pohon terbesar hingga terkecil) menggunakan 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

4.1 Menggunakan Ascending dan Descending bersamaan

  • Mengurutkan data Orange berdasarkan variabel Age secara ascending (dari umur pohon yang terkecil hingga terbesar) dan variabel Circumference secara descending (dari diamerter pohon besar hingga terkecil) dengan syntax base
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
  • Mengurutkan data Orange berdasarkan variabel Age secara ascending (dari umur pohon yang terkecil hingga terbesar) dan variabel Circumference secara descending (dari diamerter pohon besar hingga terkecil) dengan syntax dplyr
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

4.2 Perbedaan order, sort, rev, rank, dan which

Perhatikan 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
  • Ketika variabel age di 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
  • Ketika variabel age di 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
  • Ketika variabel age di 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:

  • Jika nilai yang dimiliki tidak berulang
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.

  • Jika nilai yang dimiliki berulang
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.

  • Berbeda dengan function-function sebelumnya yang digunakan untuk mengurutkan data, function which() akan mengeluarkan nilai index dari data dengan kondisi yang disyaratkan
which(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

5 Recoding Data

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
  • Menggunakan base dengan function 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
  • Menggunakan function 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
  • Menggunakan function 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

6 Merging Data

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’

  • Menggunakan base function 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>
  • Menggunakan function 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" ...
  • Menggunakan function 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

7 Reshaping Data

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
  • Mengubah data frame dari format long menjadi wide dengan function 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.

  • Mengubah data frame dari format wide menjadi long dengan function `reshape()
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.

  • Mengubah data frame dari format long menjadi wide dengan function tidyr::spread()
wide2 <- df_2%>% spread(kelas, bb)
wide2
##   jenis_kelamin   a  b  c
## 1             F 601 52 48
## 2             M  60 55 65
  • Mengubah data frame dari format wide menjadi long dengan function 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

8 Reference and Contacs

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:

https://www.linkedin.com/in/hafizah-ilma-665449141/