Lập trình với R: vapply và tapply

tapply

tapply

Ở bài viết trước, chúng ta đã học về hai hàm thành viên quan trọng trong R đó là lapply() và sapply(). Cả hai đều nhận đầu vào là list, apply một hàm tương ứng với các phần tử trong list, sau đó kết hợp và trả về kết quả cuối cùng. lapply() luôn trả về một list, trong khi sapply() cố gắng tinh giản kết quả trả về.

Trong bài viết này, ta sẽ học về cách sử dụng vapply() và tapply(), mỗi hàm đóng một vai trò nhất định vào chiến lược Split-Apply-Combine. Chúng ta sẽ sử dụng cùng tập dữ liệu ở bài viết ‘lapply và sapply’.

Tập dữ liệu Flags lấy từ UCI Machine Learning Repository chứa thông tin chi tiết về quốc kỳ của các quốc gia. Để biết thêm thông tin các bạn có thể truy cập tại trang web sau: http://archive.ics.uci.edu/ml/datasets/Flags.

vapply

Như thường lệ, chúng ta sẽ quan sát tổng quan tập dữ liệu flags.

flags <- read.csv(url("http://archive.ics.uci.edu/ml/machine-learning-databases/flags/flag.data"))

# quan sát 6 dòng đầu tiên của tập dữ liệu
head(flags)
            name landmass zone area population language religion bars stripes
1    Afghanistan        5    1  648         16       10        2    0       3
2        Albania        3    1   29          3        6        6    0       0
3        Algeria        4    1 2388         20        8        2    2       0
4 American-Samoa        6    3    0          0        1        1    0       0
5        Andorra        3    1    0          0        6        0    3       0
6         Angola        4    2 1247          7       10        5    0       2
  colours red green blue gold white black orange mainhue circles crosses
1       5   1     1    0    1     1     1      0   green       0       0
2       3   1     0    0    1     0     1      0     red       0       0
3       3   1     1    0    0     1     0      0   green       0       0
4       5   1     0    1    1     1     0      1    blue       0       0
5       3   1     0    1    1     0     0      0    gold       0       0
6       3   1     0    0    1     0     1      0     red       0       0
  saltires quarters sunstars crescent triangle icon animate text topleft
1        0        0        1        0        0    1       0    0   black
2        0        0        1        0        0    0       1    0     red
3        0        0        1        1        0    0       0    0   green
4        0        0        0        0        1    1       1    0    blue
5        0        0        0        0        0    0       0    0    blue
6        0        0        1        0        0    1       0    0     red
  botright
1    green
2      red
3    white
4      red
5      red
6    black

# quan sát số chiều của tập dữ liệu
dim(flags)
[1] 194  30

# quan sát cấu trúc của tập dữ liệu
str(flags)
'data.frame': 194 obs. of  30 variables:
 $ name      : Factor w/ 194 levels "Afghanistan",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ landmass  : int  5 3 4 6 3 4 1 1 2 2 ...
 $ zone      : int  1 1 1 3 1 2 4 4 3 3 ...
 $ area      : int  648 29 2388 0 0 1247 0 0 2777 2777 ...
 $ population: int  16 3 20 0 0 7 0 0 28 28 ...
 $ language  : int  10 6 8 1 6 10 1 1 2 2 ...
 $ religion  : int  2 6 2 1 0 5 1 1 0 0 ...
 $ bars      : int  0 0 2 0 3 0 0 0 0 0 ...
 $ stripes   : int  3 0 0 0 0 2 1 1 3 3 ...
 $ colours   : int  5 3 3 5 3 3 3 5 2 3 ...
 $ red       : int  1 1 1 1 1 1 0 1 0 0 ...
 $ green     : int  1 0 1 0 0 0 0 0 0 0 ...
 $ blue      : int  0 0 0 1 1 0 1 1 1 1 ...
 $ gold      : int  1 1 0 1 1 1 0 1 0 1 ...
 $ white     : int  1 0 1 1 0 0 1 1 1 1 ...
 $ black     : int  1 1 0 0 0 1 0 1 0 0 ...
 $ orange    : int  0 0 0 1 0 0 1 0 0 0 ...
 $ mainhue   : Factor w/ 8 levels "black","blue",..: 5 7 5 2 4 7 8 7 2 2 ...
 $ circles   : int  0 0 0 0 0 0 0 0 0 0 ...
 $ crosses   : int  0 0 0 0 0 0 0 0 0 0 ...
 $ saltires  : int  0 0 0 0 0 0 0 0 0 0 ...
 $ quarters  : int  0 0 0 0 0 0 0 0 0 0 ...
 $ sunstars  : int  1 1 1 0 0 1 0 1 0 1 ...
 $ crescent  : int  0 0 1 0 0 0 0 0 0 0 ...
 $ triangle  : int  0 0 0 1 0 0 0 1 0 0 ...
 $ icon      : int  1 0 0 1 0 1 0 0 0 0 ...
 $ animate   : int  0 1 0 1 0 0 1 0 0 0 ...
 $ text      : int  0 0 0 0 0 0 0 0 0 0 ...
 $ topleft   : Factor w/ 7 levels "black","blue",..: 1 6 4 2 2 6 7 1 2 2 ...
 $ botright  : Factor w/ 8 levels "black","blue",..: 5 7 8 7 7 1 2 7 2 2 ...

# tổng hợp thông tin về tập dữ liệu
summary(flags)
             name        landmass          zone            area        
 Afghanistan   :  1   Min.   :1.000   Min.   :1.000   Min.   :    0.0  
 Albania       :  1   1st Qu.:3.000   1st Qu.:1.000   1st Qu.:    9.0  
 Algeria       :  1   Median :4.000   Median :2.000   Median :  111.0  
 American-Samoa:  1   Mean   :3.572   Mean   :2.211   Mean   :  700.0  
 Andorra       :  1   3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:  471.2  
 Angola        :  1   Max.   :6.000   Max.   :4.000   Max.   :22402.0  
 (Other)       :188                                                    
   population         language        religion          bars       
 Min.   :   0.00   Min.   : 1.00   Min.   :0.000   Min.   :0.0000  
 1st Qu.:   0.00   1st Qu.: 2.00   1st Qu.:1.000   1st Qu.:0.0000  
 Median :   4.00   Median : 6.00   Median :1.000   Median :0.0000  
 Mean   :  23.27   Mean   : 5.34   Mean   :2.191   Mean   :0.4536  
 3rd Qu.:  14.00   3rd Qu.: 9.00   3rd Qu.:4.000   3rd Qu.:0.0000  
 Max.   :1008.00   Max.   :10.00   Max.   :7.000   Max.   :5.0000  
                                                                   
    stripes          colours           red             green       
 Min.   : 0.000   Min.   :1.000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.: 0.000   1st Qu.:3.000   1st Qu.:1.0000   1st Qu.:0.0000  
 Median : 0.000   Median :3.000   Median :1.0000   Median :0.0000  
 Mean   : 1.552   Mean   :3.464   Mean   :0.7887   Mean   :0.4691  
 3rd Qu.: 3.000   3rd Qu.:4.000   3rd Qu.:1.0000   3rd Qu.:1.0000  
 Max.   :14.000   Max.   :8.000   Max.   :1.0000   Max.   :1.0000  
                                                                   
      blue             gold            white            black      
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:1.0000   1st Qu.:0.000  
 Median :1.0000   Median :0.0000   Median :1.0000   Median :0.000  
 Mean   :0.5103   Mean   :0.4691   Mean   :0.7526   Mean   :0.268  
 3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.000  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.000  
                                                                   
     orange         mainhue      circles          crosses      
 Min.   :0.000   red    :71   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.000   blue   :40   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.000   green  :31   Median :0.0000   Median :0.0000  
 Mean   :0.134   white  :22   Mean   :0.1701   Mean   :0.1495  
 3rd Qu.:0.000   gold   :19   3rd Qu.:0.0000   3rd Qu.:0.0000  
 Max.   :1.000   black  : 5   Max.   :4.0000   Max.   :2.0000  
                 (Other): 6                                    
    saltires          quarters         sunstars         crescent     
 Min.   :0.00000   Min.   :0.0000   Min.   : 0.000   Min.   :0.0000  
 1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.: 0.000   1st Qu.:0.0000  
 Median :0.00000   Median :0.0000   Median : 0.000   Median :0.0000  
 Mean   :0.09278   Mean   :0.1495   Mean   : 1.387   Mean   :0.0567  
 3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.: 1.000   3rd Qu.:0.0000  
 Max.   :1.00000   Max.   :4.0000   Max.   :50.000   Max.   :1.0000  
                                                                     
    triangle           icon           animate           text        
 Min.   :0.0000   Min.   :0.0000   Min.   :0.000   Min.   :0.00000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.000   1st Qu.:0.00000  
 Median :0.0000   Median :0.0000   Median :0.000   Median :0.00000  
 Mean   :0.1392   Mean   :0.2526   Mean   :0.201   Mean   :0.08247  
 3rd Qu.:0.0000   3rd Qu.:0.7500   3rd Qu.:0.000   3rd Qu.:0.00000  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.000   Max.   :1.00000  
                                                                    
   topleft      botright 
 black :12   red    :69  
 blue  :43   blue   :47  
 gold  : 6   green  :40  
 green :32   white  :17  
 orange: 4   black  : 9  
 red   :56   gold   : 9  
 white :41   (Other): 3

Như ở phần trước, hàm unique() trả về một vector chứa các giá trị đơn nhất từ đối tượng truyền vào. Do đó, sapply(flags, unique) sẽ trả về list một vector chứa các giá trị đơn nhất cho từng cột dữ liệu của flags.

Khi làm việc trong môi trường tương tác (interactive at the prompt), chúng ta sẽ ít khi bị nhầm lẫn vì bạn có thể nhìn thấy kết quả ngay tức thì, từ đó có thể chỉnh sửa lại tính toán của mình. Tuy nhiên, khi làm việc trên môi trường không tương tác (non-interactively: khi viết functions), chúng ta dễ dự đoán sai kết quả trả về. Vì vậy, chúng ta cần cảnh giác hơn bằng cách sử dụng hàm vapply().

Trong khi sapply() cố gắng tinh giản kết quả trả về thì vapply() cho phép bạn lựa chọn định dạng kết quả trả về một cách tường minh. Nếu như kết quả trả về không khớp với định dạng mà bạn chọn, vapply() sẽ đưa ra thông báo lỗi và dừng hẳn chương trình. Việc làm này có thể ngăn chặn được các vấn đề quan trọng trong code của bạn khi bạn dự đoán sai kết quả trả về do nhầm lẫn.

Chúng ta sẽ thử dòng lệnh vapply(flags, unique, numeric(1)). Dòng lệnh này có nghĩa là bạn mong muốn mỗi phần tử trong kết quả trả về là numeric vector có độ dài là 1. Trong khi điều này không đúng, bạn sẽ nhận một thông báo lỗi.

vapply(flags, unique, numeric(1))
Error in vapply(flags, unique, numeric(1)) : values must be length 1,
 but FUN(X[[1]]) result is length 194

Sử dụng lại hàm sapply(flags, class) để trả về một character vector chứa tên kiểu dữ liệu cho các cột thuộc tính trong tập dữ liệu. Giả sử chúng ta muốn lựa chọn định dạng trả về như sapply() bằng cách sử dụng hàm vapply() ta sẽ làm như sau.

sapply(flags, class)
      name   landmass       zone       area population   language   religion 
  "factor"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
      bars    stripes    colours        red      green       blue       gold 
 "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
     white      black     orange    mainhue    circles    crosses   saltires 
 "integer"  "integer"  "integer"   "factor"  "integer"  "integer"  "integer" 
  quarters   sunstars   crescent   triangle       icon    animate       text 
 "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
   topleft   botright 
  "factor"   "factor"

vapply(flags, class, character(1))
      name   landmass       zone       area population   language   religion 
  "factor"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
      bars    stripes    colours        red      green       blue       gold 
 "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
     white      black     orange    mainhue    circles    crosses   saltires 
 "integer"  "integer"  "integer"   "factor"  "integer"  "integer"  "integer" 
  quarters   sunstars   crescent   triangle       icon    animate       text 
 "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
   topleft   botright 
  "factor"   "factor"

Đối số ‘character(1)’ mách cho R biết rằng chúng ta mong muốn hàm class() trả về một character vector có độ dài là 1 khi áp dụng lên từng cột thuộc tính của Flags. Dĩ nhiên, kết quả trả về tương tự như hàm sapply().

Bạn có thể nghĩ rằng vapply() sẽ an toàn hơn sapply(), khi nó đòi hỏi bạn phải chỉ định kết quả trả về, thay vì để R cố gắng tinh giản kết quả cho bạn. Thêm vào đó, vapply() có tốc độ xử lý nhanh hơn sapply() trên tập dữ liệu lớn. Tuy nhiên, khi phân tích dữ liệu theo kiểu tương tác (interactively at the prompt), sapply() sẽ tiết kiệm thời gian trong việc nhập lệnh.

tapply

Khi phân tích dữ liệu, bạn muốn tách dữ liệu của mình thành các nhóm dựa trên giá trị của một vài cột thuộc tính. Sau đó, ta áp dụng một function lên các thành viên trong nhóm này. Hàm tiếp theo chúng ta sẽ khảo sát đó là tapply(), sẽ hỗ trợ chúng ta làm điều này.

Cột thuộc tính ‘landmass’ trong tập dữ liệu gồm các giá trị integer nằm trong khoảng 1 và 6, mỗi giá trị thể hiện một phần khác nhau trên bản đồ thế giới. Sử dụng hàm table() để xem có bao nhiêu flags/countries nằm trong từng nhóm trên.

table(flags$landmass)
 1  2  3  4  5  6 
31 17 35 52 39 20 

Cột thuộc tính ‘animate” trong tập dữ liệu chứa giá trị 1 nếu quốc kì của quốc gia đó chứa một biểu tượng animate (ví dụ như một con chim ưng, một cái cây, một bàn tay) và 0 ngược lại. Sử dụng hàm table() để xem có bao nhiêu quốc kì chứa các biểu tượng này.

table(flags$animate)
  0   1 
155  39

Kết quả trên cho chúng ta biết có 39 quốc kì chứa các biểu tượng animate (animate = 1) và 155 không có animate (animate = 0).

Sử dụng hàm tapply(flags$animate, flags$landmass, mean) để tính giá trị trung bình cho cột thuộc tính ‘animate’ ứng với từng châu lục ‘landmass’. Khi đó, ta sẽ có số lượng trung bình của các quốc kì có biểu tượng ‘animate’ nằm trong từng châu lục.

tapply(flags$animate, flags$landmass, mean)
        1         2         3         4         5         6 
0.4193548 0.1764706 0.1142857 0.1346154 0.1538462 0.3000000

Châu lục đầu tiên (landmass = 1) thuộc North America có tỉ lệ cao nhất so với các châu lục còn lại về số quốc kì có biểu tượng animate (0.4194).

Trong bài viết này, chúng ta đã học về cách sử dụng hàm vapply() để có kết quả trả về an toàn hơn thay vì sử dụng hàm sapply(), hàm này đặc biệt hữu ích khi bạn viết functions của riêng mình. Đồng thời, chúng ta cũng đã học cách sử dụng hàm tapply() để tách dữ liệu của chúng ta thành từng nhóm dựa trên giá trị của một vài cột thuộc tính, sau đó áp dụng một hàm tính toán nào đó lên từng nhóm này. Các hàm này sẽ hỗ trợ bạn thao tác tốt hơn trong quá trình phân tích dữ liệu.

Nguồn tham khảo: http://swirlstats.com/

Advertisements

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s