See more in [http://www.cookbook-r.com/Manipulating_data/Recoding_data/]
Xử lý dữ liệu với data set mtcars

require(tidyr)
## Loading required package: tidyr
require(plyr)
## Loading required package: plyr
require(ggplot2)
## Loading required package: ggplot2
require(reshape2)
## Loading required package: reshape2
df <- mtcars
head(df)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
str(df)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

1. Mã hóa dữ liệu

Data set mtcars được lấy từ tạp chí Motor Trend US trong năm 1974, bao gồm dữ liệu về tiêu thụ nhiên liệu và 10 đặc điểm thiết kế của 32 loại xe ô tô. Data set có 11 biến số: mpg: tiêu thụ nhiên liệu (dặm/gallon), cyl: số xy lanh, disp, hp: công suất, drat: tỷ số xoắn…

Trong data set am là kiểu hộp số được mã hóa với 2 giá trị 0 (số tự động), 1(số điều khiển bằng tay). Chúng ta sẽ mã hóa lại biến số am thành dạng factor với tên lần lượt là automaticmanual và gán cho một biến số mới có tên là trans. ## 1.1. Mã hóa dữ liệu dạng thứ bậc

df$trans <- factor(df$am, levels=c(0, 1), labels=c("Automatic", "Manual"))

Sử dụng package(plyr).

Chú ý: hàm relevel() chỉ làm việc với biến dạng factor.

require(plyr)
df$am <- as.factor(df$am)
df$trans2 <- revalue(df$am, c("0"="Automatic", "1"="Manual"))
df$trans3 <- mapvalues(df$am, from=c("0", "1"), to = c("Automatic", "Manual"))
levels(df$trans3)
## [1] "Automatic" "Manual"

Sử dụng R’s built-in function

df$trans4[df$am=="0"] <- "Automatic"
df$trans4[df$am=="1"] <- "Manual"

Sử dụng match() function

oldvalues <- c("0", "1")
newvalues <- factor(c("Automatic", "Manual"))
df$trans <- newvalues[match(df$am, oldvalues)]

1.2. Mã hóa dữ liệu dạng liên tục

Giả sử chúng ta muốn mã hóa dữ liệu công suất của 32 dòng ô tô thành 3 nhóm: cao (H), trung bình (M), thấp (L) và gán các giá trị này vào một biến số mới có tên power.

df$power[df$hp < 96.5] <- "L"
df$power[df$hp >180] <- "H"
df$power[96.5 <= df$hp & df$hp <=180] <- "M"

Sử dụng hàm cut

df$power <- cut(df$hp,
                breaks=c(-Inf, 96.5, 180, Inf),
                labels=c("L", "M", "H"))
# By default, the ranges are open on the left and closed on the right as (96.5, 180]

2. Converting between vector types

2.1. Numeric to character and factor

df <- mtcars
df$vs <- factor(df$vs)
# We can also specify the order of levels when we create the variables or transforming it
df$vs <- factor(mtcars$vs, levels=c("0", "1"))
df$vs1 <- factor(mtcars$vs, levels=c("1", "0"))
df$vs2 <- as.character(mtcars$vs)
str(df)
## 'data.frame':    32 obs. of  13 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : Factor w/ 2 levels "0","1": 1 1 2 2 1 2 1 2 2 2 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
##  $ vs1 : Factor w/ 2 levels "1","0": 2 2 1 1 2 1 2 1 1 1 ...
##  $ vs2 : chr  "0" "0" "1" "1" ...

2.2. Character to factor and numeric

df$vs2 <- as.numeric(df$vs2)
df$vs2 <- as.factor(as.character(mtcars$vs))

2.3. Factor to character and numeric

Đổi dữ liệu từ dạng factor sang dạng character rất dễ dàng bằng lệnh as.character().

df$vs1 <- as.character(df$vs)

Biến đổi từ dạng factor sang dạng numeric phức tạp hơn. Nếu chỉ sử dụng as.numeric() thì chỉ có số mã hóa cho factor được chuyển sang dạng số. Do vậy, trước hết ta biến đổi biến factor sang dạng character sau đó mới chuyển về sạng số.

df$vs2 <- as.numeric(as.character(df$vs2))
str(df)
## 'data.frame':    32 obs. of  13 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : Factor w/ 2 levels "0","1": 1 1 2 2 1 2 1 2 2 2 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
##  $ vs1 : chr  "0" "0" "1" "1" ...
##  $ vs2 : num  0 0 1 1 0 1 0 1 1 1 ...

3. Sắp xếp dữ liệu

3.1. Sắp xếp dữ liệu dạng vector, using sort() function

v <- sample(100:110)
sort(v, decreasing=TRUE)
##  [1] 110 109 108 107 106 105 104 103 102 101 100

3.2. Sắp xếp data frames using arrange() function in package plyr

df <- data.frame(id = 1:4,
                 weight = c(20, 27, 24, 22),
                 size = c("small", "large", "medium", "large"))
df
##   id weight   size
## 1  1     20  small
## 2  2     27  large
## 3  3     24 medium
## 4  4     22  large
require(plyr)
# Sắp xếp theo weight
arrange(df, weight)
##   id weight   size
## 1  1     20  small
## 2  4     22  large
## 3  3     24 medium
## 4  2     27  large
# Sắp xếp theo size sau đó theo weight
arrange(df, size, weight, decreasing= TRUE)
##   id weight   size
## 1  1     20  small
## 2  3     24 medium
## 3  2     27  large
## 4  4     22  large

Mặc định của arrange là sắp xếp theo thứ tự tăng dần, nếu muốn cột nào đó được sắp xếp theo tứ tự giảm dần có thể thêm desc vào trước tên cột đó.

arrange(df, size, desc(weight))
##   id weight   size
## 1  2     27  large
## 2  4     22  large
## 3  3     24 medium
## 4  1     20  small
  • Chú ý: biến dạng factor sẽ được sắp xếp theo thứ tự của levels*

4. Factors

4.1. Đặt lại bậc (levels) của factor

  • Sử dụng revalue() hoặc mapvalues() từ package plyr*
str(df)
## 'data.frame':    4 obs. of  3 variables:
##  $ id    : int  1 2 3 4
##  $ weight: num  20 27 24 22
##  $ size  : Factor w/ 3 levels "large","medium",..: 3 1 2 1
levels(df$size)
## [1] "large"  "medium" "small"
df$size <- revalue(df$size, c("large"="L", "small"="S", "medium"="M"))
df$size <- mapvalues(df$size, from=c("S","M","L"), to=c("Small", "Medium", "Large"))

4.2. Tính tại thứ bậc của factor: hoặc sử dụng factor() hoặc droplevels()

Việc này được thực hiện khi một biến factor có một hay nhiều bậc thực tế không tồn tại trong data xảy ra khi nhập dữ liệu hoặc loại bỏ bớt một số dòng trong data.

x <- factor(c("alpha", "beta", "alpha"), levels=c("alpha", "beta", "gama"))
x
## [1] alpha beta  alpha
## Levels: alpha beta gama
x <- factor(x)
x
## [1] alpha beta  alpha
## Levels: alpha beta

Sau khi nhập dữ liệu, data frame có thể chứa đồng thời nhiều biến dạng factor cùng với các biến số dạng khác, trong trường hợp này chúng ta có thể tính lại bậc của tất cả các biến factor bằng cách sử dụng droplevels() function.

# Create a data frame with extra level
df <- data.frame(x=factor(c("alpha", "beta", "alpha"), levels=c("alpha", "beta", "gamma")),
                 y=c(5,8,2),
                 z=factor(c("red", "green", "green"), levels=c("red", "green", "blue")))
str(df)
## 'data.frame':    3 obs. of  3 variables:
##  $ x: Factor w/ 3 levels "alpha","beta",..: 1 2 1
##  $ y: num  5 8 2
##  $ z: Factor w/ 3 levels "red","green",..: 1 2 2
df <- droplevels(df)
str(df)
## 'data.frame':    3 obs. of  3 variables:
##  $ x: Factor w/ 2 levels "alpha","beta": 1 2 1
##  $ y: num  5 8 2
##  $ z: Factor w/ 2 levels "red","green": 1 2 2

4.3. Thay đổi thứ bậc của biến fator

Có 2 loại biến factor trong R: biến factor dạng thứ bậc (ordered) và dạng không thứ bậc(unordered). Cách thứ nhất để thay đổi thứ tự các level là sử dụng hàm factor() lên factor và chỉ ra thứ tự một cách trực tiếp. Cách thứ 2 là sử dụng hàm ordered().

str(df)
## 'data.frame':    3 obs. of  3 variables:
##  $ x: Factor w/ 2 levels "alpha","beta": 1 2 1
##  $ y: num  5 8 2
##  $ z: Factor w/ 2 levels "red","green": 1 2 2
df$x <- factor(df$x, levels=c("beta", "alpha"))
str(df)
## 'data.frame':    3 obs. of  3 variables:
##  $ x: Factor w/ 2 levels "beta","alpha": 2 1 2
##  $ y: num  5 8 2
##  $ z: Factor w/ 2 levels "red","green": 1 2 2

Một cách khác để thay đổi thứ bậc là sử dụng hàm relevel(), khi đó một bậc cụ thể sẽ được đưa lên đầu, các bậc còn lại được lùi một bậc. Chú ý cách này không áo dụng với các biến factor dạng thứ bậc.

str(df)
## 'data.frame':    3 obs. of  3 variables:
##  $ x: Factor w/ 2 levels "beta","alpha": 2 1 2
##  $ y: num  5 8 2
##  $ z: Factor w/ 2 levels "red","green": 1 2 2
x <- factor(df$x)
x
## [1] alpha beta  alpha
## Levels: beta alpha
x <- relevel(x, "alpha")
# câu lệnh sau đây sẽ cho ra lỗi
x <- ordered(df$x)
#x
#x <- relevel(x,"alpha")

5. Làm việc với data frame

5.1. Đổi tên cột trong data frame

df <- data.frame(alpha=1:3, beta=4:6, gamma=7:9)
df
##   alpha beta gamma
## 1     1    4     7
## 2     2    5     8
## 3     3    6     9
require(plyr)
df <- rename(df, c("alpha"="A", "beta"="B"))

***NOTE: sử dụng chỉ số kiểu ma trận để lấy một phần data frame cho các kết quả khác nhau khi chúng ta chỉ lấy một cột trong data frame. Trong trường hợp này kết quả trả về là một vector. Để tránh điều này chúng ta nên sử dụng chỉ số kiểu danh sách (list) hoặc sử dụng drop=FALSE.

5.2. Nối 2 data frame sử dụng function merge()

stories2 <- read.table(header=TRUE, text='
   id       title
    1       lions
    2      tigers
    3       bears
')
data <- data <- read.table(header=TRUE, text='
    subject storyid rating
          1       1    6.7
          1       2    4.5
          1       3    3.7
          2       2    3.3
          2       3    4.1
          2       1    5.2
')
merge(x=stories2, y=data, by.x="id", by.y="storyid")
##   id  title subject rating
## 1  1  lions       1    6.7
## 2  1  lions       2    5.2
## 3  2 tigers       1    4.5
## 4  2 tigers       2    3.3
## 5  3  bears       1    3.7
## 6  3  bears       2    4.1

Như vậy lệnh merge sẽ kiểm tra xem giá trị nào của cột id trong stories2 giống giá trị trong cột storyid trong data để nối 2 data frame lại với nhau. Trong ví dụ trên, merge tìm được giá trị 1 trong cột id của stories2, sau đó merge tìm các giá trị 1 trong cột storyid của data và add thêm giá trị của các dòng tương tứng vào data frame mới, loại bỏ cột storyid.

Ngoài ra lệnh merge cũng cho phép nối nhiều cột trong 2 data frame với nhau.

animals <- read.table(header=T, text='
   size type         name
  small  cat         lynx
    big  cat        tiger
  small  dog    chihuahua
    big  dog "great dane"
    cat  dog         dog
')

observations <- read.table(header=T, text='
   number  size type
        1   big  cat
        2 small  dog
        3 small  dog
        4   big  dog
')
merge(animals, observations, c("size", "type"))
##    size type       name number
## 1   big  cat      tiger      1
## 2   big  dog great dane      4
## 3 small  dog  chihuahua      2
## 4 small  dog  chihuahua      3

*NOTE: merge() tìm giá trị trong cột size và type tương ứng trong animals, sau đó tìm xem có các giá trị đó trong size và type của observations hay không. Nếu không có, ví dụ: small cat không có trong observations, vì vậy trong data frame mới không có giá trị này. Ngược lại với giá trị small dog, merge() tìm thấy 2 dòng tương ứng trong data nên nó trả về kết quả 2 dòng.

6. Chuyển đổi dữ liệu dạng bảng ngắn và bảng dài

Có 2 phương pháp chính để chuyển đổi giữa dữ liệu dạng bảng ngắn và bảng dài.
- gather()spread() trong package tidyr - melt()dcast() trong package reshape2

Tạo 2 data frame có dạng bảng rộng (nhiều cột) và bảng dài (ít cột)

df_wide <- read.table(header=TRUE, text='
 subject sex control cond1 cond2
       1   M     7.9  12.3  10.7
       2   F     6.3  10.6  11.1
       3   F     9.5  13.1  13.8
       4   M    11.5  13.4  12.9
')
df_wide$subject <- factor(df_wide$subject)

df_long <- read.table(header=TRUE, text='
 subject sex condition measurement
       1   M   control         7.9
       1   M     cond1        12.3
       1   M     cond2        10.7
       2   F   control         6.3
       2   F     cond1        10.6
       2   F     cond2        11.1
       3   F   control         9.5
       3   F     cond1        13.1
       3   F     cond2        13.8
       4   M   control        11.5
       4   M     cond1        13.4
       4   M     cond2        12.9
')
df_long$subject <- factor(df_long$subject)

6.1. Chuyển đổi với package tidyr

Rộng \(\rightarrow\) dài sử dụng gather()

data_long <- gather(df_wide, condition, measurement, control:cond2)

Dài \(\rightarrow\) rộng sử dụng spread()

spread(df_long, condition, measurement)
##   subject sex cond1 cond2 control
## 1       1   M  12.3  10.7     7.9
## 2       2   F  10.6  11.1     6.3
## 3       3   F  13.1  13.8     9.5
## 4       4   M  13.4  12.9    11.5

6.2. Chuyển đổi với package reshape2

Rộng \(\rightarrow\) dài sử dụng melt()

melt(df_wide, 
     id.vars=c("subject", "sex"), 
     variable.name = "Treatment",
     measure.vars = c("control","cond1", "cond2"),
     value.name = "Measurement")
##    subject sex Treatment Measurement
## 1        1   M   control         7.9
## 2        2   F   control         6.3
## 3        3   F   control         9.5
## 4        4   M   control        11.5
## 5        1   M     cond1        12.3
## 6        2   F     cond1        10.6
## 7        3   F     cond1        13.1
## 8        4   M     cond1        13.4
## 9        1   M     cond2        10.7
## 10       2   F     cond2        11.1
## 11       3   F     cond2        13.8
## 12       4   M     cond2        12.9

Dài \(\rightarrow\) rộng sử dụng dcast()

dcast(df_long, subject+sex ~ condition,
      value.var="measurement")
##   subject sex cond1 cond2 control
## 1       1   M  12.3  10.7     7.9
## 2       2   F  10.6  11.1     6.3
## 3       3   F  13.1  13.8     9.5
## 4       4   M  13.4  12.9    11.5

7. Chuyển đổi giữa data frame và bảng

cases <- data.frame(
    Sex=c("M", "M", "F", "F", "F"), 
    Color=c("brown", "blue", "brown", "brown", "brown")
)
cases
##   Sex Color
## 1   M brown
## 2   M  blue
## 3   F brown
## 4   F brown
## 5   F brown
# Contigency table

ctable <- table(cases)

# table with count of each combination

counts <- data.frame(
    Sex=c("F", "M", "F", "M"), 
    Color=c("blue", "blue", "brown", "brown"),
    Freq=c(0, 1, 3, 1)
)
counts
##   Sex Color Freq
## 1   F  blue    0
## 2   M  blue    1
## 3   F brown    3
## 4   M brown    1

Cases sang Counts

countdf <- as.data.frame(table(cases))
countdf
##   Sex Color Freq
## 1   F  blue    0
## 2   M  blue    1
## 3   F brown    3
## 4   M brown    1

Count to case fucntion

Convert from data frame of counts to data frame of cases.

countcol is the name of the column containing the counts

countsToCases <- function(x, countcol = “Freq”) { # Get the row indices to pull from x idx <- rep.int(seq_len(nrow(x)), x[[countcol]])

# Drop count column
x[[countcol]] <- NULL

# Get the rows from x
x[idx, ]

} ## Contigency table to Cases ctable <- table(cases) ctable cases <- countsToCases(as.data.frame(ctable)) ````

Tạo vector dạng số để subset dữ liệu…

rep(1, 4)
## [1] 1 1 1 1
# Lặp lại các giá trị theo các số khác nhau. Ví dụ lặp lại 1 2 lần 2 4 lần 3 6 lần
unlist(mapply(rep, 1:3, seq(2,6, by=2)))
##  [1] 1 1 2 2 2 2 3 3 3 3 3 3