Hands-on Data Science with R
January 2022
Phân tích dữ liệu với R - Phần I
Trong nội dung này, chúng ta cùng làm quen với các kiểu dữ liệu và cấu trúc dữ liệu thường dùng trong R.
Dữ liệu thường gặp được lưu trữ trong R có thể bắt gặp ở 4 dạng sau:
numeric
integer
logical
character
Các kiểu dữ liệu trong R
Các kiểu dữ liệu chính
Dữ liệu kiểu Numeric ở đây là số thực, ví dụ như 2.345, số pi,…
Dữ liệu kiểu Integer ở đây là kiểu dữ liệu số nguyên, trong R số nguyên được định nghĩa là thêm hậu tố L vào sau phần số. Ví dụ: 2L, 3L, 8L…
Dữ liệu kiểu Logical là dữ liệu kiểu dạng logic TRUE hoặc FALSE.
Dữ liệu kiểu Character là dữ liệu kiểu chuỗi, xâu ký tự, giống như Python, dữ liệu kiểu này được đặt trong dấu ‘text’ hoặc “text”.
Cấu trúc dữ liệu
Khi lưu trữ dữ liệu, trong R phân thành các dạng dữ liệu mà nội dung trong cấu trúc đó dữ liệu có thể là đồng nhất (kiểu dữ liệu là như nhau - homogeneous), hoặc các dữ liệu lưu trữ là khác kiểu nhau (heterogenous).
Về cấu trúc dữ liệu dạng lưu trữ, các dạng phổ biến thường gặp trong R và trong khoa học dữ liệu bao gồm:
vectors
matrices
lists
data frames
Data Structures in R
Kiểu Véc tơ
Vectơ là một chuỗi một chiều của các phần tử dữ liệu cùng kiểu.
Các vectơ được xây dựng với hàm c (). Để gán một vectơ cho một biến, hãy sử dụng toán tử <- . Hàm c() là viết tắt của concatenation - cho phép ghép, kết nối các phần tử lại với nhau. Ví dụ:
# Một véc tơ các phần tử số
<- c(1L,2L,3L,3.14)
x x
## [1] 1.00 2.00 3.00 3.14
Dấu mũi tên chỉ ra là toán tử gán, không giống như các ngôn ngữ lập trình khác, sử dụng dấu =. Trong R sử dụng dấu mũi tên để làm toán tử gán (assignment operator).
Để biết được kiểu dữ liệu trong các cấu trúc dữ liệu là gì, chúng ta sử dụng hàm str()
<- c(1L,2L,3L,3.14)
x str(x)
## num [1:4] 1 2 3 3.14
Trong một số trường hợp chúng ta quan tâm tới số phần tử của véc tơ hay nói cách khác là chiều dài của véc tơ, sử dụng hàm length()
<- c(1L,2L,3L,3.14)
x print(length(x))
## [1] 4
Kết quả trả về là 4 phần tử. Hàm c() còn cho chúng ta kết nối các véc tơ con khác nhau như sau:
<- c(1L,2L,3L,3.14)
x <- c(1,2,3,5,4,6)
y <- c(x, y)
z z
## [1] 1.00 2.00 3.00 3.14 1.00 2.00 3.00 5.00 4.00 6.00
# Ghép các véc tơ con
<- c(x,y,z, c(1,2,3,4,5,6))
t t
## [1] 1.00 2.00 3.00 3.14 1.00 2.00 3.00 5.00 4.00 6.00 1.00 2.00 3.00 3.14 1.00
## [16] 2.00 3.00 5.00 4.00 6.00 1.00 2.00 3.00 4.00 5.00 6.00
Trong cấu trúc dữ liệu kiểu Véc tơ, chúng ta sử dụng một số hàm chức năng khác để thao tác với cấu trúc dữ liệu này:
Sử dụng hàm seq(from=…, to=…, by=…) để tạo ra một chuỗi số cách đều nhau. Trong đó cho phép chúng ta tạo ra một véc tơ số bất kỳ với tham số by có nghĩa là khoảng cách giữa các số.
Sử dụng toán tử slicing (:) . Giống với Python, R cung cấp toán tử trượt (slicing operator) để thao tác với véc tơ.
<- seq(from = 1, to = 5, by = 1) num1 <- c(1:8) num2 num1
## [1] 1 2 3 4 5
num2
## [1] 1 2 3 4 5 6 7 8
# Viết tóm tắt <- seq(1,5,1) num3 num3
## [1] 1 2 3 4 5
Bài tập áp dụng:
- Hãy tạo một véc tơ số từ 1 đến 50, khoảng cách giữa các số liên tiếp là 3 đơn vị.
- Tạo ra một véc tơ số có dạng (1,2,3,…,30,29,28,…,1).
- Tạo ra một véc tơ số theo biểu thức \(e^xcos(x)\). Với x là một véc tơ có giá trị (1,2,3,4,…10)
Kiểu Factor
Factors là một cấu trúc dữ liệu đặc biệt để làm việc với dữ liệu phân loại. Dữ liệu phân loại biểu thị dữ liệu chỉ khác nhau theo nhãn (chẳng hạn như ‘có’ / ‘không’) hoặc xếp hạng (chẳng hạn như ‘thứ nhất’, ‘thứ hai’, v.v.). Trong R, Factors là một kiểu đặc biệt của vectơ số nguyên có nhãn.
# Tạo ra một véc tơ factor
<- factor(c('M', 'T', 'W', 'Th', 'F', 'M', 'W'),
weekday_factor levels = c('M', 'T', 'W', 'Th', 'F'),
labels = c('Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday'))
weekday_factor
## [1] Monday Tuesday Wednesday Thursday Friday Monday Wednesday
## Levels: Monday Tuesday Wednesday Thursday Friday
Hàm str () sẽ cho chúng ta biết rằng vectơ là factors, hiển thị một số cấp độ và hiển thị ánh xạ cơ bản của các cấp độ. Hàm summary () sẽ tự động đếm sự xuất hiện của các nhãn nhân tố.
str(weekday_factor)
## Factor w/ 5 levels "Monday","Tuesday",..: 1 2 3 4 5 1 3
summary(weekday_factor)
## Monday Tuesday Wednesday Thursday Friday
## 2 1 2 1 1
Các véc tơ factor cũng có thể được tạo bằng các vectơ số làm đầu vào. Giả sử chúng ta có một vectơ gồm các số 0 và 1 (giả sử dữ liệu của biến nhị phân nào đó được mã hóa), trong đó 1 biểu thị sự xuất hiện của một sự kiện và 0 là không xuất hiện. Đoạn mã dưới đây cho biết cách tạo một yếu tố được gắn nhãn từ dữ liệu.
<- c(1, 0, 0, 1, 0, 0)
event_indicator
<- factor(event_indicator,
event_fct levels = c(0, 1),
labels = c('No', 'Yes'))
summary(event_fct)
## No Yes
## 4 2
Sử dụng hàm levels() cho phép xem các cấp độ của biến factor:
levels(event_fct)
## [1] "No" "Yes"
Theo mặc định, nếu không cung cấp đầu vào cho các đối số cấp độ và nhãn trong factor (), các cấp sẽ tự động được gán theo thứ tự bảng chữ cái (đối với vectơ ký tự) hoặc thứ tự số. Các nhãn sau đó được đặt thành các giá trị mức.
<- factor(c('Yes', 'No', 'No', 'Yes'))
fct_from_chr
str(fct_from_chr)
## Factor w/ 2 levels "No","Yes": 2 1 1 2
<- factor(c(1, 1, 1, 4, 5))
fct_from_num
str(fct_from_num)
## Factor w/ 3 levels "1","4","5": 1 1 1 2 3
Thực hành với factor:
Giả sử chúng ta có một biến khảo sát (survey) dưới đây ghi lại mức độ hài lòng của khách hàng khi về dịch vụ phục vụ của nhân viên và thanh toán tiền khi vào trung tâm mua sắm ở một siêu thị tại thành phố Thái Nguyên, với các mức độ được đưa ra như sau:
- Không hài lòng
- Hài lòng
- Rất hài lòng
Hãy sử dụng kiến thức về factor, thống kê xem trong phiếu khảo sát trên có bao nhiêu người hài lòng, không hài lòng, rất hài lòng với chất lượng dịch vụ phục vụ?
Luật ép kiểu trong R (Coercion Rules in R)
Tất cả các phần tử của vectơ phải cùng kiểu. Khi kết hợp các kiểu dữ liệu khác nhau thành một vectơ, véc tơ đó sẽ bị ép kiểu dữ liệu theo thứ tự ưu tiên sau:
character
numeric
integer
logical
Điều này có nghĩa là nếu kết hợp các phần tử ký tự với phần tử số và số nguyên, thì tất cả các phần tử sẽ được chuyển đổi thành ký tự - character (vì nó có mức độ ưu tiên cao hơn).
<- c(2.45, 5.1, 1L, 'character')
vector_1 str(vector_1)
## chr [1:4] "2.45" "5.1" "1" "character"
Chú ý rằng R chuyển đổi các giá trị logic theo cách sau: TRUE trở thành 1 và FALSE trở thành 0.
<- c(4.234, 10L, TRUE, T, FALSE)
vector_2 str(vector_2)
## num [1:5] 4.23 10 1 1 0
<- c(10L, 5L, TRUE, FALSE)
vector_3 str(vector_3)
## int [1:4] 10 5 1 0
Kiểu Ma trận
Ma trận là một cấu trúc dữ liệu R lưu trữ một tập hợp dữ liệu được sắp xếp trong một bảng 2 chiều với các hàng và cột. Giống như vectơ, tất cả các phần tử dữ liệu của ma trận phải cùng kiểu.
Nếu chúng ta xây dựng một ma trận với các vectơ với các kiểu dữ liệu khác nhau, ma trận sẽ bị ép kiểu dữ liệu với các quy tắc ưu tiên tương tự như đã nói ở phía trên. Ma trận không thể lưu trữ cột số cũng như cột ký tự. Ma trận đầu ra khi này sẽ là một ma trận chuyển thành kiểu ký tự.
Chúng ta có thể tạo ma trận bằng hàm matrix (). Các vectơ được tạo bằng hàm c (). Với ma trận sẽ được chuyển thành cbind () hoặc rbind (). Đoạn mã dưới đây thể hiện các hàm này:
Để biết được tên hàng hoặc tên cột trong ma trận, sử dụng rownames() và colnames()
# Tạo ma trận A kích thước 2x2
<- matrix(data = c(1, 2, 3, 4), # Dữ liệu được đưa vào
A nrow = 2, # Số hàng của ma trận
ncol = 2, # Số cột của ma trận
byrow = TRUE) # Đọc dữ liệu theo hàng, mặc định là FALSE
# Sử dụng hàm dim() để kiểm tra chiều của ma trận
dim(A)
## [1] 2 2
# Xem ma trận A
A
## [,1] [,2]
## [1,] 1 2
## [2,] 3 4
Ma trận có thể được tạo ra từ một véc tơ số định nghĩa sẵn
<- c(1:9)
vector2 <- matrix(vector2, nrow = 3, ncol = 3, byrow = TRUE)
B B
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
## [3,] 7 8 9
Sử dụng cbind() để nối cột và rbind() để nối hàng
# Tạo 2 véc tơ số và ghép vào nhau.
<- c(1:4)
myvec1 <- c(5:8)
myvec2 cbind(myvec1, myvec2) -> C
C
## myvec1 myvec2
## [1,] 1 5
## [2,] 2 6
## [3,] 3 7
## [4,] 4 8
# Xem tên cột
colnames(C)
## [1] "myvec1" "myvec2"
# Tạo ma trận theo hàng với rbind()
<- rbind(myvec1, myvec2)
D D
## [,1] [,2] [,3] [,4]
## myvec1 1 2 3 4
## myvec2 5 6 7 8
# Xem tên hàng
rownames(D)
## [1] "myvec1" "myvec2"
Kiểu List (Danh sách)
Giống như ma trận, danh sách là đối tượng R có thể chứa nhiều vectơ. Nhưng không giống như ma trận, chúng là một chiều và có thể lưu trữ các kiểu dữ liệu hỗn hợp. Kiểu dữ liệu này rất giống với kiểu List của Python.
Ưu điểm của danh sách là chúng có thể chứa nhiều loại dữ liệu khác nhau với độ dài và kích thước khác nhau. Hãy coi danh sách như các vectơ đặc biệt có thể lưu trữ các cấu trúc dữ liệu khác nhau ở mỗi vị trí. Danh sách có thể đệ quy, nghĩa là một danh sách có thể chứa một danh sách.
Danh sách rất quan trọng vì hầu hết đầu ra từ các mô hình thống kê trong R, chẳng hạn như hồi quy tuyến tính hoặc phân cụm, được trả về dưới dạng danh sách.
Danh sách được tạo bằng hàm list (). Để lấy nội dung được đặt tên của một danh sách, nếu có, hãy sử dụng hàm names ().
Ví dụ: Chúng ta muốn khởi tạo một list có tên là my_list, trong list này có chứa các kiểu dữ liệu khác nhau (chuỗi ký tự, số thập phân, một ma trận , một list con khác). Lưu ý: List có thể tự đệ quy chính nó (trong list chứa một list khác như trong trường hợp này).
<- list(char_vector = c('A', 'B'),
my_list numeric_vector = c(1.2, 3.4, 5, 12.01),
a_matrix = cbind(c(1, 2), c(3, 4)),
a_list = list(c(1L, 4L), c('A', 'D', 'E')))
my_list
## $char_vector
## [1] "A" "B"
##
## $numeric_vector
## [1] 1.20 3.40 5.00 12.01
##
## $a_matrix
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
##
## $a_list
## $a_list[[1]]
## [1] 1 4
##
## $a_list[[2]]
## [1] "A" "D" "E"
Sử dụng hàm names() để liệt kê các thành phần của my_list
names(my_list)
## [1] "char_vector" "numeric_vector" "a_matrix" "a_list"
Data Frames
Cấu trúc dữ liệu phổ biến nhất trong R là dataframe. Đây là dạng dữ liệu kiểu list có 2 chiều, trong đó các biến số được liệt kê theo dòng và các cột có thể coi là các quan sát (observations). Để khởi tạo dataframe từ các vector, sử dụng data.frame().
Lưu ý: Các véc tơ trong kiểu cấu trúc dữ liệu này phải có chiều dài bằng nhau.
Để lấy tên của các biến trong khung dữ liệu, hãy sử dụng tên () hoặc colnames (). Để lấy số hàng trong khung dữ liệu, hãy sử dụng nrow () hoặc dim ().
Để lấy tên các cột biến, sử dụng names() hoặc colnames() . Để lấy được số hàng (số quan sát của dữ liệu). Sử dụng nrow() hoặc dim() . Dim ở đây là viết tắt của dimension (chiều dữ liệu). Ví dụ:
# Khởi tạo dataframe gồm 4 biến số (4 véc tơ cùng chiều dài.)
<- data.frame(student_id = c(100234, 132454, 453123),
my_data test_1_grade = c(82, 93, 87),
hw_1_grade = c(92, 89, 98),
session = c("7 AM", "7 PM", "7 AM"))
my_data
## student_id test_1_grade hw_1_grade session
## 1 100234 82 92 7 AM
## 2 132454 93 89 7 PM
## 3 453123 87 98 7 AM
# Xem số quan sát
nrow(my_data)
## [1] 3
# Xem chiều của dữ liệu
dim(my_data)
## [1] 3 4
Toán tử và dữ liệu con
Các phép toán số học
R cung cấp các toán tử thường gặp như cộng trừ nhân chia đối với tất cả các phép toán. Có một điều lưu ý là khi thực hiện các phép tính (mathematical expressions) này với một véc tơ số, tất cả các phần tử của véc tơ đều được tính toán theo.
<- c(1,2,3,4,5)
v1 <- (5:9)
v2 + v2 v1
## [1] 6 8 10 12 14
- v2 v1
## [1] -4 -4 -4 -4 -4
* v2 v1
## [1] 5 12 21 32 45
/v2 v1
## [1] 0.2000000 0.3333333 0.4285714 0.5000000 0.5555556
5*v1 + 6*v2
## [1] 35 46 57 68 79
Các toán tử quan hệ
Kết quả của phép toán này là True hoặc False, các phần tử trong từng véc tơ được so sánh với nhau và đưa ra giá trị dưới dạng True hoặc False.
<- c(1,1,2,3,4)
v3 <- c(2,3,4,5,1)
v4 > v4 v3
## [1] FALSE FALSE FALSE FALSE TRUE
>= v4 v3
## [1] FALSE FALSE FALSE FALSE TRUE
!= v4 v3
## [1] TRUE TRUE TRUE TRUE TRUE
So sánh AND: Khi muốn so sánh các điều kiện xảy ra đồng thời, sử dụng phép toán AND (&). Nếu sử dụng phép so sánh OR (Sử dụng ký hiệu | ).
Cấu trúc dữ liệu con
Trong trường hợp chúng ta muốn trích xuất dữ liệu từ các véc tơ và lọc ra các phần tử thỏa mãn điều kiện nào đó, sử dụng các toán tử như []; [[]] hoặc $
Tập véc tơ con
Chúng ta có thể tách các phần tử của tập véc tơ ban đầu thành các véc tơ con khác thỏa mãn một điều kiện cho trước như sau:
# Tìm các tập con của myvec1 thỏa mãn các phần tử > 3
<- c(1,2,3,4,5)
myvec1 > 3 myvec1
## [1] FALSE FALSE FALSE TRUE TRUE
Như vậy có 2 phần tử là 4 và 5 của myvec1 thỏa mãn. Để liệt kê chính xác các phần tử này, sử dung toán tử []
# Liệt kê chính xác giá trị các phần tử.
<- c(1,2,3,4,5)
myvec1 > 3] myvec1[myvec1
## [1] 4 5
# Kết hợp với điều kiện bổ sung
< 2 | myvec1 > 3] myvec1[myvec1
## [1] 1 4 5
Giống như Python, có thể truy cập vào từng phần tử của véc tơ thông qua slicing operator (toán tử trượt). Tuy nhiên phần tử đầu tiên trong véc tơ đánh chỉ số (index) từ 1 không phải là số 0!
<- c(1,2,3,4,5)
myvec1 # Truy cập vào phần tử cuối của myvec1, hàm length() trả về độ dài véc tơ
length(myvec1)] myvec1[
## [1] 5
# Lấy dữ liệu phần tử thứ 1 và thứ 3
c(1,3)] myvec1[
## [1] 1 3
Tập con danh sách
Danh sách là một nội dung phổ biến và thường dùng trong khoa học dữ liệu, tính chất của nó đặc trưng bởi việc nó cho phép lưu trữ dữ liệu ở nhiều dạng khác nhau.
Danh sách là tập hợp của nhiều cấu trúc dữ liệu khác nhau. Để truy cập các cấu trúc dữ liệu được lưu trữ trong danh sách, chúng ta có thể sử dụng các hàm [], [[]] hoặc $.
Ví dụ nếu chúng ta có một danh sách là my_list, thì my_list [1] trả về một danh sách có phần tử đầu tiên của my_list. Điều này khác với my_list [[1]], trả về nội dung của phần tử đầu tiên của my_list.
# Khởi tạo danh sách
<- list(student_id = c(12, 15),
student_list section = c('001', '003'),
age = c(26, 20))
# Lấy phần tử đầu tiên của danh sách trên
1] student_list[
## $student_id
## [1] 12 15
# Truy xuất vào các phần tử trong phần tử đầu tiên
1]] student_list[[
## [1] 12 15
# Truy xuất vào phần tử đầu tiên của phần tử thứ nhất trong student_list
$student_id[1] student_list
## [1] 12
Tập Dataframe con
Để tập hợp con các hàng và cột của khung dữ liệu, chúng ta có thể sử dụng cú pháp sau:
my_data_frame [điều kiện hàng, điều kiện cột]
# Khởi tạo dataframe
<- data.frame(make = c("Toyota","Honda","Vinfast", "Toyota",
my_data_frame "Ford", "Honda"),
mpg = c(34, 33, 22, 32, 29, 27),
cylinders = c(4, 4, 8, 6, 6, 8))
my_data_frame
## make mpg cylinders
## 1 Toyota 34 4
## 2 Honda 33 4
## 3 Vinfast 22 8
## 4 Toyota 32 6
## 5 Ford 29 6
## 6 Honda 27 8
# Truy cập theo chỉ số dòng, cột
# Truy cập vào dòng 1 đến dòng 3, cột 1 và cột 2
1:3,1:2] my_data_frame[
## make mpg
## 1 Toyota 34
## 2 Honda 33
## 3 Vinfast 22
# Truy cập dòng 2, cột 1 và cột 2
2, c(1,2)] my_data_frame[
## make mpg
## 2 Honda 33
# Truy cập dòng 2, 3 và tất cả các cột
c(2,3),] my_data_frame[
## make mpg cylinders
## 2 Honda 33 4
## 3 Vinfast 22 8
Chỉ số Logic
Chúng ta cũng có thể chuyển các vectơ logic vào điều kiện hàng để có được một tập con dữ liệu của chúng ta. Giả sử chúng ta muốn tìm các dữ liệu trong tập dữ liệu my_data_frame các dòng xe ô tô có dung tích xi lanh lớn hơn hoặc bằng 6.
# Kiểm tra điều kiện logic
<- my_data_frame$cylinders >= 6
logical_condition logical_condition
## [1] FALSE FALSE TRUE TRUE TRUE TRUE
my_data_frame[logical_condition, ]
## make mpg cylinders
## 3 Vinfast 22 8
## 4 Toyota 32 6
## 5 Ford 29 6
## 6 Honda 27 8
Thực tế, các nội dung trên có thể tóm gọn lại như sau:
$cylinders >= 6, ] my_data_frame[my_data_frame
## make mpg cylinders
## 3 Vinfast 22 8
## 4 Toyota 32 6
## 5 Ford 29 6
## 6 Honda 27 8
Mở rộng dữ liệu DATAFRAME
Vì bản chất dữ liệu của Dataframe này là một danh sách (List), để trích xuất dữ liệu từ dataframe, chúng ta có thể sử dụng tách dữ liệu từ dataframe như dạng list
# Trích xuất dữ liệu theo vector, lấy cột đầu tiên của dataframe
1]] -> value1
my_data_frame[[ value1
## [1] "Toyota" "Honda" "Vinfast" "Toyota" "Ford" "Honda"
Thực hành:
Trong nội dung này, chúng ta sẽ thực hành với bài tập kiểu list như sau, tập dữ liệu về điểm trung bình, tuổi và id của các sinh viên của một lớp học.
<- list(classes_offered = c("MIS 431", "MIS 310", "MIS 410", "MIS 412"),
my_list student_data = data.frame(student_id = c(54, 100, 32, 423,
2, 19, 39),
age = c(18, 22, 27, 18, 29,
22, 20),
gpa = c(3.1, 2.8, 3.7, 3.4, 3.2,
3.4, 3.2),
stringsAsFactors = FALSE))
Viết mã R để tính giá trị trung vị của biến gpa trong tập student_data.
Gợi ý viết hàm median()
<- function(x){
my_median # Sắp xếp dữ liệu theo chiều tăng hoặc giảm dần trước
<- sort(x)
x # Nếu số phần tử của véc tơ x là chẵn
if((length(x) %% 2) == 0){
return((x[length(x)/2] + x[length(x)/2 + 1]) / 2)
}# Nếu số phần tử của véc tơ x là lẻ
else{
return(x[(length(x)/2) + 0.5])
} }
Các hàm sắp xếp sort(), order() và rank()
Đây là ba hàm cơ bản về sắp xếp theo thứ bậc của dữ liệu. Hàm sort theo mặc định sẽ sắp xếp dữ liệu theo chiều giảm dần. Hàm order cho phép hiển thị ra chỉ mục dòng của dữ liệu gốc sau khi đã sắp xếp và hàm rank cho phép hiển thị các chỉ mục theo thứ hạng (mặc định số bé nhất có hạng là 1). Chúng ta cùng quan sát hình sau để thấy rõ sự khác biệt giữa ba hàm này.
Sắp xếp chỉ số
Chúng ta cùng đến với một ví dụ cụ thể như sau: Trong tập dữ liệu murders của gói dslabs có chứa thông tin về dân số và số lượng tội phạm sử dụng súng tại 51 bang của nước Mỹ được thống kê bởi FBI vào năm 2010, hãy sử dụng các hàm sắp xếp trên để đưa ra thông tin:
Liệt kê ra tên của 5 Bang có số lượng tội phạm lớn nhất Mỹ, các Bang này nằm ở các dòng nào của dữ liệu?
Liệt kê ra tên của 5 Bang có số lượng dân số thấp nhất nước Mỹ, các Bang này nằm ở các dòng nào của dữ liệu?
library(dslabs)
data("murders")
# Lưu trữ véc tơ tên của các Bang, số tội phạm
<- murders$total
toipham <- murders$state
states <- murders$population
population # Tạo chỉ mục véc tơ dùng order
<- order(-murders$total)
index # Liệt kê theo tên các Bang có tội phạm lớn nhất
<- data.frame(states[index], toipham[rank(index)], rank(index))
mydata1 c("State","Number of murders","Index Row") -> tenbien
colnames(mydata1) <- tenbien
head(mydata1, n = 5)
## State Number of murders Index Row
## 1 California 1257 5
## 2 Texas 805 44
## 3 Florida 669 10
## 4 New York 517 33
## 5 Pennsylvania 457 39
# Liệt kê ra 5 bang có số dân thấp nhất của Mỹ
<- order(murders$population)
index2 <- data.frame(states[index2], population[rank(index2)], rank(index2))
mydata2 c("State","Population","Index Row") -> tenbien1
colnames(mydata2) <- tenbien1
head(mydata2, n = 5)
## State Population Index Row
## 1 Wyoming 563626 51
## 2 District of Columbia 601723 9
## 3 Vermont 625741 46
## 4 North Dakota 672591 35
## 5 Alaska 710231 2
Z-score
Trong phân tích dữ liệu thống kê, z-score là một nội dung rất quan trọng mà chúng ta cần quan tâm. Điểm z rất quan trọng vì là cơ sở trong xác suất thống kê, chúng ta cần làm rõ ba câu hỏi:
Điểm z (z-score) là gì
Tại sao lại cần sử dụng điểm z
Điểm z dùng làm gì?
Giả sử chúng ta có kết quả điểm thi như sau
Môn thi | Điểm thi của bạn | Điểm trung bình của lớp | Độ lệch chuẩn |
---|---|---|---|
Tin học Đại Cương | 26/60 | 31.7 | 5.5 |
Lập trình Python | 37/70 | 50.1 | 10.6 |
Câu hỏi đặt ra là: Bạn đạt điểm thi môn nào tốt hơn, Python hay Tin Đại cương? và làm thế nào để đánh giá được.
Để trả lời cho câu hỏi này, chúng ta có ba cách:
So sánh mức điểm cần đạt với mức yêu cầu (So sánh thang điểm 10)
So sánh với điểm trung bình của cả lớp
So sánh với các bạn trong lớp, xem là mình ở vị trí thứ bao nhiêu
Việc quan trọng trong câu hỏi này là chúng ta nên quy chuẩn về cùng một thang điểm và so sánh, điều này còn được gọi là chuẩn hóa. Ví dụ chuyển thang điểm 60 và 70 ở trên về cùng một tháng điểm 10
Như vậy điểm z-score còn gọi là điểm chuẩn z, là phương pháp chuẩn hóa bằng cách chuyển giá trị thô thành thang điểm độ lệch chuẩn (so với giá trị trung bình).
Chúng ta có công thức tính điểm z như sau, đối với tổng thể và mẫu
\[ z-score=\frac{X-\mu}{\sigma} \]
\[ z-score=\frac{X-\bar{X}}{S} \]
Môn thi | Điểm thi của bạn | Điểm trung bình của lớp | Độ lệch chuẩn | z-score |
---|---|---|---|---|
Tin học Đại Cương | 26/60 | 31.7 | 5.5 | -1.04 |
Lập trình Python | 37/70 | 50.1 | 10.6 | -1.24 |
Để tính điểm z-score trong R, chúng ta làm như sau:
<- c(8, 7, 7, 10, 13, 14, 15, 16, 18)
data <- function(x){
zscore <- (x-mean(x))/sd(x)
z_scores return(z_scores)
}
zscore(data)
## [1] -0.9701425 -1.2126781 -1.2126781 -0.4850713 0.2425356 0.4850713 0.7276069
## [8] 0.9701425 1.4552138
Phân phối chuẩn của điểm z
Như vậy giá trị điểm z của một quan sát chính là khoảng cách từ quan sát đó đến giá trị trung bình, đây là bản chất của điểm z. Phân phối chuẩn của điểm z rất quan trọng vì dựa vào phân phối của z có thể tính xác suất của quan sát.
Điểm z có thể sử dụng cho 4 mục đích:
Điểm z được sử dụng để tính % phân vị
Để tính khoảng cách giữa hai quan sát
Để so sánh hai quan sát có thang điểm khác nhau
Để xác định giá trị ngoại biên (outlier)
Chúng ta cùng quan sát lại giá trị điểm z và % phân vị của hai môn học quan sát ở phía trên và tính điểm z cho các giá trị là 26 và 37
Để tính % phân vị cho điểm z, chúng ta sử dụng hàm pnorm()
<- c(-1.04, -1.24)
diemthi_zcore pnorm(diemthi_zcore)
## [1] 0.1491700 0.1074877
% phân vị cho các quan sát
Như vậy đối với môn học Tin học Đại cương chúng ta có điểm % z-score là 14.9% thì vùng da cam chiếm 14.9%, phần còn lại là: 85.1%, hay nói cách khác là bạn đang đứng ở phân vị thứ 14.9%, nếu lớp học có 100 người thì bạn đứng thứ 15.
Hoàn toàn tương tự như vậy đối với môn Lập trình Python thì % z-score là 10.7% hay bạn đứng ở vị trí thứ 11 nếu lớp có 100 bạn.
Điểm z-score được sử dụng để tính khoảng cách giữa hai quan sát. Quan sát một ví dụ như sau:
z-score để sử dụng để tính khoảng cách giữa hai quan sát
Dựa vào hình trên, chúng ta thấy là khoảng cách giữa hai người A và B là 71.7%
Điều quan trọng nhất của điểm z là so sánh hai quan sát có thang đo khác nhau như trong trường hợp này. Ngoài ra điểm z-score còn được dùng để xác định giá trị ngoại lai (outlier).
Giá trị ngoại lai
Phân tích dữ liệu cơ bản
Trong nội dung này, chúng ta cùng bàn chi tiết về phân tích dữ liệu trong R với sự trợ giúp của hệ sinh thái tidyverse
Khái niệm hàm
Function được định nghĩa là hàm trong lập trình, giúp cho người lập trình tiết kiệm thời gian, linh hoạt hơn trong việc xử lý tính toán và phân tích dữ liệu. Hàm được viết ra để giúp ngắn thời gian viết code lệnh và tăng khả năng thực thi và xử lý lệnh lặp lại trong chương trình.
Trong R và các ngôn ngữ khác, khái niệm built-in functions ám chỉ các hàm được xây dựng sẵn và chỉ cần truyền tham số vào hàm là có thể sử dụng được. Một số hàm thống kê cơ bản trong R có thể liệt kê là:
min() Đưa ra giá trị nhỏ nhất
max() Đưa ra giá trị lớn nhất
range() Đưa ra giá trị khoảng biến thiên của dữ liệu
median() Đưa ra giá trị trung vị của dữ liệu
fivenum() Kết quả đưa ra là một véc tơ gồm 5 giá trị bao gồm: giá trị nhỏ nhất, tứ phân vị 25, trung vị, tứ phân vị 75, giá trị lớn nhất
quantile() Đưa ra giá tị của phân vị do người dùng định nghĩa
Giả sử chúng ta có một véc tơ số như sau:
<- c(1,2,3,5,1,2,3,8,4,12,19,30,21,12)
myvector1 min(myvector1)
## [1] 1
max(myvector1)
## [1] 30
median(myvector1)
## [1] 4.5
range(myvector1)
## [1] 1 30
# Phân vị 30 %
quantile(myvector1, 0.3)
## 30%
## 2.9
# Phân vị 30, 60 và 90
quantile(myvector1, c(0.3, 0.6, 0.9))
## 30% 60% 90%
## 2.9 7.4 20.4
fivenum(myvector1)
## [1] 1.0 2.0 4.5 12.0 30.0
Tổng và tổng tích lũy
Sử dụng hàm cum và cumsum để tính tổng tích lũy
<- c(1:9)
myvector2 sum(myvector2)
## [1] 45
cumsum(myvector2)
## [1] 1 3 6 10 15 21 28 36 45
Hàm rank
Hàm này cho phép sắp xếp theo thứ hạng của từng phần tử trong tập dữ liệu. Mặc định, phần tử có giá trị nhỏ nhất sẽ có hàng là 1.
<- c(-2, 4.5, -6, 10, 12)
negative_data abs(negative_data) -> abs_data
rank(abs_data)
## [1] 1 2 3 4 5
rank(-abs_data)
## [1] 5 4 3 2 1
Xây dựng hàm trong R
Thông thường để xây dựng (viết) hàm trong R, chúng ta sử dụng cú pháp như sau:
Xây dựng hàm trong R
Trong nội dung này, chúng ta sẽ cùng xây dựng một số hàm cơ bản trong thống kê như sau:
- Hàm trả về giá trị tính tổng của véc tơ
- Hàm trả về giá trị min(hoặc max) của một véc tơ
- Hàm tính phương sai, độ lệch chuẩn của một véc tơ
- Hàm tính hiệp phương sai, hiệp biến (covariance) của một véc tơ
- Hàm tính hệ số tương quan Pearson của hai biến tuân theo phân phối chuẩn.
# Xây dựng véc tơ x gồm 10 phần tử từ 1 đến 10
<- c(1:10)
z # Xây dựng hàm tính tổng các phần tử của một véc tơ
<- function(x){
tinhtong = 0
tong for(i in 1:length(x)){
= tong + x[i]
tong
}return(tong)
}# Kiểm tra hàm xây dựng
tinhtong(z)
## [1] 55
sum(z)
## [1] 55
sum(z) == tinhtong(z)
## [1] TRUE
# Xây dựng hàm tìm giá trị nhỏ nhất
<- function(x) {
min_value = x[1]
my_min for (i in seq_along(x)) {
if (x[i] < my_min) my_min = x[i]
}return(my_min)
}# Kiểm tra hàm
min_value(z)
## [1] 1
# Viết hàm xác định tính chẵn, lẻ của một số, chia module %%, chia integer %/%
<- function(x){
chanle if(x %% 2 == 0){
print(paste0(x,": là số chẵn"))
}else{
print(paste0(x,": là số lẻ"))
}
}# Test hàm
chanle(5)
## [1] "5: là s<U+1ED1> l<U+1EBB>"
# Sử dụng hàm ifelse(condition, TRUE, FALSE)
<- 1:5
x ifelse(x %%2 == 0, paste0(x,": là số chẵn"), paste0(x, ": là số lẻ"))
## [1] "1: là s<U+1ED1> l<U+1EBB>" "2: là s<U+1ED1> ch<U+1EB5>n"
## [3] "3: là s<U+1ED1> l<U+1EBB>" "4: là s<U+1ED1> ch<U+1EB5>n"
## [5] "5: là s<U+1ED1> l<U+1EBB>"
# Viết hàm tính tổng, trung bình, phương sai, min, max của một véc tơ số
<- function(x){
tong = 0
total for(i in 1:length(x)){
= total + x[i]
total
}return (total)
}
# Test hàm
<- c(1:100)
y tong(y)
## [1] 5050
# Hàm tính giá trị trung bình
<- function(x){
trungbinh <- tong(x)/length(x)
trungbinh_x return(trungbinh_x)
}# Test hàm
trungbinh(y)
## [1] 50.5
# Hàm tính phương sai của một véc tơ số
<- function(x){
phuongsai <- (x - trungbinh(x))^2
binhphuong = 0
total for (i in 1:length(x)){
= total + binhphuong[i]
total
}= total/(length(x)-1)
ketqua return(ketqua)
}# Test hàm
phuongsai(y)
## [1] 841.6667
var(y)
## [1] 841.6667
# Xây dựng hàm tính độ lệch chuẩn
<- function(x){
ham_sd = sqrt(phuongsai(x))
ketqua return(ketqua)
}ham_sd(y)
## [1] 29.01149
sd(y)
## [1] 29.01149
# Hàm tính giá trị nhỏ nhất
<- function(x){
ham_min = x[1]
nhonhat for(i in 1:length(x)){
if (nhonhat > x[i]){
= x[i]
nhonhat
}
}return(nhonhat)
}# Test hàm
ham_min(y)
## [1] 1
min(y)
## [1] 1
# Viết hàm tính hệ số tương quan giữa 2 biến số trong R
# Viết hàm tính hiệp phương sai covariance
<- function(x, y){
covariance = (x - mean(x))*(y-mean(y))
a = 0
sum if(length(x) == length(y)){
for (i in 1:length(x)){
= sum + a[i]
sum
}
}else {
print("Hai véc tơ phải cùng chiều dài!")
break
}return(sum/(length(x)-1))
}<- c(1:9)
x1 <- c(2:10)
y1 covariance(x1, y1)
## [1] 7.5
cov(x1,y1)
## [1] 7.5
# Tương quan Pearson
<- function(x, y){
pearson <- covariance(x, y)/(sqrt(phuongsai(x)*phuongsai(y)))
heso return(heso)}
Giới thiệu về Tidyverse
Phần này sẽ trình bày những kiến thức cơ bản về thao tác dữ liệu bằng cách sử dụng thư viện tidyverse. Tidyverse là một hệ sinh thái gồm các thư viện chuyên biệt được thiết kế cho việc phân tích khoa học dữ liệu.
Thao tác dữ liệu cơ bản
Trong nội dung này, chúng ta cùng xem xét tập dữ liệu Employee Attrition Data (Phân bổ nhân viên). Dữ liệu bao gồm 1.470 hồ sơ nhân viên cho một công ty kinh doanh sản phẩm có trụ sở tại Hoa Kỳ.
Để hiểu rõ các biến số của tập dữ liệu này, tham khảo bảng sau đây:
library(readr)
library(dplyr)
library(skimr)
## Warning: package 'skimr' was built under R version 4.1.2
<- read_rds("employee_data.rds")
employee_data
# View data
%>%
employee_data head(n=10)
## # A tibble: 10 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 1.19e5 56 Rarely
## 2 No Sales Senior Man~ 8.56e4 42 Frequently
## 3 Yes Product Develop~ Associate 4.62e4 56 Rarely
## 4 No IT and Analytics Director 1.17e5 50 Frequently
## 5 No Sales Associate 3.66e4 46 Rarely
## 6 No Marketing Senior Man~ 8.35e4 48 Frequently
## 7 No Marketing Senior Man~ 8.86e4 44 Rarely
## 8 No Sales Director 1.22e5 47 Rarely
## 9 No Finance and Ope~ Senior Man~ 9.46e4 50 Frequently
## 10 No Product Develop~ Director 1.25e5 51 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
skim(employee_data, left_company, department, salary, weekly_hours)
Name | employee_data |
Number of rows | 1470 |
Number of columns | 13 |
_______________________ | |
Column type frequency: | |
factor | 2 |
numeric | 2 |
________________________ | |
Group variables | None |
Variable type: factor
skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
---|---|---|---|---|---|
left_company | 0 | 1 | FALSE | 2 | No: 1233, Yes: 237 |
department | 0 | 1 | FALSE | 6 | IT : 399, Res: 293, Sal: 252, Mar: 238 |
Variable type: numeric
skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
---|---|---|---|---|---|---|---|---|---|---|
salary | 0 | 1 | 94076.25 | 37590.24 | 29848.56 | 70379.48 | 88555.53 | 117099.9 | 212134.7 | ▃▇▃▁▁ |
weekly_hours | 0 | 1 | 50.02 | 4.82 | 40.00 | 47.00 | 49.00 | 52.0 | 66.0 | ▂▇▃▂▁ |
Sau đây chúng ta cùng thao tác với một vài hàm xử lý dữ liệu cơ bản:
# Lọc ra dữ liệu các nhân viên rời công ty
filter(employee_data, left_company == "Yes") %>%
head()
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 1.19e5 56 Rarely
## 2 Yes Product Development Associate 4.62e4 56 Rarely
## 3 Yes Marketing Manager 6.39e4 57 Rarely
## 4 Yes Finance and Operat~ Manager 5.65e4 58 Rarely
## 5 Yes Marketing Director 1.09e5 54 Rarely
## 6 Yes Research Director 1.19e5 62 Frequently
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Lọc dữ liệu với nhân viên rời công ty, làm ở bộ phận Sales
filter(employee_data, left_company == "Yes", department == "Sales") %>%
head()
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 118681. 56 Rarely
## 2 Yes Sales Associate 38539. 57 Rarely
## 3 Yes Sales Manager 82916. 63 Frequently
## 4 Yes Sales Associate 37529. 60 Rarely
## 5 Yes Sales Associate 44875. 59 Rarely
## 6 Yes Sales Senior Manager 95996. 60 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Lọc dữ liệu với nhân viên làm bộ phân Sales hoặc Marketing
filter(employee_data, department == "Sales" | department == "Marketing") %>%
head()
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 118681. 56 Rarely
## 2 No Sales Senior Manager 85576. 42 Frequently
## 3 No Sales Associate 36635. 46 Rarely
## 4 No Marketing Senior Manager 83520. 48 Frequently
## 5 No Marketing Senior Manager 88556. 44 Rarely
## 6 No Sales Director 122281. 47 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Sử dụng toán tử %in% lặp lại công việc như trên
filter(employee_data, department %in% c('Sales', 'Marketing')) %>%
head()
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 118681. 56 Rarely
## 2 No Sales Senior Manager 85576. 42 Frequently
## 3 No Sales Associate 36635. 46 Rarely
## 4 No Marketing Senior Manager 83520. 48 Frequently
## 5 No Marketing Senior Manager 88556. 44 Rarely
## 6 No Sales Director 122281. 47 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Tìm ra các nhân viên có lương trên 80000 và làm ở bộ phận Sales hoặc Marketing
filter(employee_data, salary > 80000, department %in% c('Sales', 'Marketing')) %>%
head()
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 118681. 56 Rarely
## 2 No Sales Senior Manager 85576. 42 Frequently
## 3 No Marketing Senior Manager 83520. 48 Frequently
## 4 No Marketing Senior Manager 88556. 44 Rarely
## 5 No Sales Director 122281. 47 Rarely
## 6 No Sales Director 122821. 46 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Lựa chọn các biến hiển thị
select(employee_data, left_company, department, job_level) %>%
head()
## # A tibble: 6 x 3
## left_company department job_level
## <fct> <fct> <fct>
## 1 Yes Sales Director
## 2 No Sales Senior Manager
## 3 Yes Product Development Associate
## 4 No IT and Analytics Director
## 5 No Sales Associate
## 6 No Marketing Senior Manager
# Cách khác lựa chọn cột chỉ số 1,2,3
# select(employee_data, c(1, 2, 3))
# Không hiển thị các biến job_level, department
select(employee_data, -department, -job_level) %>%
head()
## # A tibble: 6 x 11
## left_company salary weekly_hours business_travel yrs_at_company
## <fct> <dbl> <dbl> <fct> <int>
## 1 Yes 118681. 56 Rarely 6
## 2 No 85576. 42 Frequently 10
## 3 Yes 46236. 56 Rarely 0
## 4 No 117227. 50 Frequently 8
## 5 No 36635. 46 Rarely 2
## 6 No 83520. 48 Frequently 7
## # ... with 6 more variables: yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Hiển thị tất cả các biến có chứa từ khóa là job
select(employee_data, contains('job')) %>%
head()
## # A tibble: 6 x 2
## job_level job_satisfaction
## <fct> <fct>
## 1 Director Very High
## 2 Senior Manager Medium
## 3 Associate High
## 4 Director High
## 5 Associate Medium
## 6 Senior Manager Very High
# Hiển thị tất cả các biến có bắt đầu bằng ký tự y
select(employee_data, starts_with("y")) %>%
head()
## # A tibble: 6 x 2
## yrs_at_company yrs_since_promotion
## <int> <int>
## 1 6 0
## 2 10 1
## 3 0 0
## 4 8 3
## 5 2 2
## 6 7 3
# Sắp xếp tăng dần theo tình trạng và lương
arrange(employee_data, left_company, salary) %>%
head()
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 No IT and Analytics Associate 29849. 50 Rarely
## 2 No Marketing Associate 30559. 48 Rarely
## 3 No Sales Associate 32306. 50 Rarely
## 4 No Product Development Associate 32444. 48 None
## 5 No Research Associate 33277. 49 Frequently
## 6 No Research Associate 33319. 52 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Thống kê lương trung bình của toàn nhân viên
summarise(employee_data, average_salary = mean(salary))
## # A tibble: 1 x 1
## average_salary
## <dbl>
## 1 94076.
# thống kê tổng quan một số đại lượng khác
summarise(employee_data, salary_min = min(salary),
salary_25th = quantile(salary, 0.25),
salary_50th = median(salary),
salary_75th = quantile(salary, 0.75),
salary_max = max(salary))
## # A tibble: 1 x 5
## salary_min salary_25th salary_50th salary_75th salary_max
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 29849. 70379. 88556. 117100. 212135.
# Tính z-score cho biến salary
<- mutate(employee_data,
employee_data_scaled salary_scaled = (salary - mean(salary))/sd(salary))
select(employee_data_scaled, salary, salary_scaled) %>%
head()
## # A tibble: 6 x 2
## salary salary_scaled
## <dbl> <dbl>
## 1 118681. 0.655
## 2 85576. -0.226
## 3 46236. -1.27
## 4 117227. 0.616
## 5 36635. -1.53
## 6 83520. -0.281
Thao tác dữ liệu nâng cao
Trong nội dung này, chúng ta cùng tìm hiểu thêm một số thao tác phân tích dữ liệu nâng cao, sử dụng toán tử pipe (%>%) trong thư viện dplyr. Để tìm hiểu về toán tử pipe, xem thêm ở đây.
Thống kê theo nhóm
Tiếp tục tìm hiểu về tập dữ liệu phân bổ nhân viên việc làm, cùng tìm hiểu về dữ liệu để trả lời cho câu hỏi sau: Đối với những nhân viên đã rời công ty thì số giờ làm việc có lớn hơn giờ làm việc trung bình/tuần của tất cả các nhân viên không?
# Khởi tạo một biến mới theo z-score đặt tên là hours_scaled
%>%
employee_data mutate(hours_scaled = (weekly_hours - mean(weekly_hours)) / sd(weekly_hours)) %>%
filter(left_company == 'Yes') %>%
summarise(avg_weekly_hours = mean(hours_scaled))
## # A tibble: 1 x 1
## avg_weekly_hours
## <dbl>
## 1 1.78
Theo dữ liệu được phân tích ở trên, chúng ta đã chuẩn hóa thành z-score cho biến giờ làm việc, khi đó giờ trung bình làm việc sẽ quy đổi về 0 với tất cả các nhân viên. Như vậy với các nhân viên đã rời công ty thì xu hướng đều làm việc nhiều hơn so với trung bình với các nhân viên khác là khoảng gần 2 tiếng (1.78 giờ).
Bây giờ, chúng ta sẽ đến với một câu hỏi khác: Hãy tính giá trị lương trung bình của tất cả các nhân viên theo các phòng ban chức năng?
%>%
employee_data group_by(department) %>% # Sắp xếp theo nhóm phòng ban
summarise(average_salary = mean(salary)) # Thống kê theo từng nhóm
## # A tibble: 6 x 2
## department average_salary
## <fct> <dbl>
## 1 Marketing 93266.
## 2 Sales 90149.
## 3 Research 99425.
## 4 Product Development 92429.
## 5 IT and Analytics 93898.
## 6 Finance and Operations 93893.
Mở rộng thêm vấn đề, liệu lương trung bình của tất cả các phòng ban này đối với các đối tượng vẫn đang làm việc và các đối tượng hiện không còn làm việc có sự khác biệt hay không?
%>%
employee_data group_by(left_company, department) %>% # Nhóm theo tình trạng làm việc và phòng ban chức năng
summarise(average_salary = mean(salary)) # Tính toán thống kê theo tổ hợp nhóm
## `summarise()` has grouped output by 'left_company'. You can override using the
## `.groups` argument.
## # A tibble: 12 x 3
## # Groups: left_company [2]
## left_company department average_salary
## <fct> <fct> <dbl>
## 1 No Marketing 98656.
## 2 No Sales 96305.
## 3 No Research 100321.
## 4 No Product Development 98406.
## 5 No IT and Analytics 94137.
## 6 No Finance and Operations 100265.
## 7 Yes Marketing 66582.
## 8 Yes Sales 76158.
## 9 Yes Research 71157.
## 10 Yes Product Development 77131.
## 11 Yes IT and Analytics 90950.
## 12 Yes Finance and Operations 77657.
Một kết quả khá hiển nhiên là với những nhân viên đã rời công ty thì lương của họ khi còn ở vị trí công tác tại các phòng chức năng thấp hơn so với các đối tượng hiện đang công tác.
Có thể hiển thị kết quả trên theo một cách khác để tiện so sánh hơn:
%>%
employee_data group_by( department,left_company) %>% # Nhóm theo tình trạng làm việc và phòng ban chức năng
summarise(average_salary = mean(salary)) # Tính toán thống kê theo tổ hợp nhóm
## `summarise()` has grouped output by 'department'. You can override using the
## `.groups` argument.
## # A tibble: 12 x 3
## # Groups: department [6]
## department left_company average_salary
## <fct> <fct> <dbl>
## 1 Marketing No 98656.
## 2 Marketing Yes 66582.
## 3 Sales No 96305.
## 4 Sales Yes 76158.
## 5 Research No 100321.
## 6 Research Yes 71157.
## 7 Product Development No 98406.
## 8 Product Development Yes 77131.
## 9 IT and Analytics No 94137.
## 10 IT and Analytics Yes 90950.
## 11 Finance and Operations No 100265.
## 12 Finance and Operations Yes 77657.
Kết hợp với mutate để tính z-score cho từng nhân viên theo các bộ phận phòng ban
%>%
employee_data group_by(department) %>%
mutate(salary_scaled_dept = (salary - mean(salary)) / sd(salary)) %>%
select(department, salary_scaled_dept) %>%
head()
## # A tibble: 6 x 2
## # Groups: department [4]
## department salary_scaled_dept
## <fct> <dbl>
## 1 Sales 0.756
## 2 Sales -0.121
## 3 Product Development -1.24
## 4 IT and Analytics 0.624
## 5 Sales -1.42
## 6 Marketing -0.267
Trong trường hợp chúng ta muốn so sánh độ lệch không phải cho toàn bộ các nhân viên mà so sánh độ lệch về lương của từng nhân viên cho từng nhóm, thao tác như sau:
%>%
employee_data mutate(salary_scaled = (salary - mean(salary)) / sd(salary)) %>% # Chuẩn hóa cho toàn bộ nhân viên
group_by(department) %>% # Sắp xếp theo nhóm
mutate(salary_scaled_dept = (salary - mean(salary)) / sd(salary)) %>% # Chuẩn hóa cho từng nhóm riêng biệt
select(department, salary_scaled, salary_scaled_dept) %>%
head()
## # A tibble: 6 x 3
## # Groups: department [4]
## department salary_scaled salary_scaled_dept
## <fct> <dbl> <dbl>
## 1 Sales 0.655 0.756
## 2 Sales -0.226 -0.121
## 3 Product Development -1.27 -1.24
## 4 IT and Analytics 0.616 0.624
## 5 Sales -1.53 -1.42
## 6 Marketing -0.281 -0.267
Group_by và skim
Hàm skim cho phép tạo thống kê theo nhóm rất nhanh và tiện dụng
# Thống kê toàn bộ tập dữ liệu theo phòng ban chức năng
#employee_data %>%
# group_by(department) %>%
#skim()
# Thống kê theo biến lựa chọn
%>% group_by(department) %>%
employee_data skim(left_company, salary)
Name | Piped data |
Number of rows | 1470 |
Number of columns | 13 |
_______________________ | |
Column type frequency: | |
factor | 1 |
numeric | 1 |
________________________ | |
Group variables | department |
Variable type: factor
skim_variable | department | n_missing | complete_rate | ordered | n_unique | top_counts |
---|---|---|---|---|---|---|
left_company | Marketing | 0 | 1 | FALSE | 2 | No: 198, Yes: 40 |
left_company | Sales | 0 | 1 | FALSE | 2 | No: 175, Yes: 77 |
left_company | Research | 0 | 1 | FALSE | 2 | No: 284, Yes: 9 |
left_company | Product Development | 0 | 1 | FALSE | 2 | No: 128, Yes: 50 |
left_company | IT and Analytics | 0 | 1 | FALSE | 2 | No: 369, Yes: 30 |
left_company | Finance and Operations | 0 | 1 | FALSE | 2 | No: 79, Yes: 31 |
Variable type: numeric
skim_variable | department | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
---|---|---|---|---|---|---|---|---|---|---|---|
salary | Marketing | 0 | 1 | 93265.58 | 36514.10 | 30559.08 | 72344.72 | 87856.66 | 117603.1 | 206581.5 | ▂▇▃▁▁ |
salary | Sales | 0 | 1 | 90148.67 | 37746.84 | 30488.15 | 66664.75 | 85180.55 | 116104.2 | 197965.1 | ▅▇▅▁▂ |
salary | Research | 0 | 1 | 99425.10 | 37606.81 | 33276.54 | 73047.08 | 91205.32 | 119657.4 | 203528.9 | ▂▇▅▁▂ |
salary | Product Development | 0 | 1 | 92429.42 | 37322.31 | 32443.79 | 68360.73 | 87066.84 | 114993.6 | 195345.4 | ▅▇▅▁▂ |
salary | IT and Analytics | 0 | 1 | 93897.64 | 37367.83 | 29848.56 | 70115.29 | 88521.84 | 116088.1 | 211621.0 | ▃▇▃▁▁ |
salary | Finance and Operations | 0 | 1 | 93893.34 | 39945.11 | 37115.29 | 70317.59 | 88760.26 | 113516.5 | 212134.7 | ▆▇▃▁▂ |
Thống kê dòng với n() và count()
Hàm n() và count() cho phép thống kê số lượng dòng theo từng nhóm kết hợp với sử dụng group_by()
# Thống kê tổng số nhân viên đã rời công ty và đang làm việc
%>% group_by(left_company) %>%
employee_data summarise(number_employees = n())
## # A tibble: 2 x 2
## left_company number_employees
## <fct> <int>
## 1 No 1233
## 2 Yes 237
Hàm count() cho phép thao tác thống kê đếm với trường hợp sử dụng cho biến factor không quá nhiều giá trị. Ví dụ câu hỏi đặt ra: Hãy thống kê số lượng sinh viên theo từng phòng ban chức năng của công ty?
%>%
employee_data count(department)
## # A tibble: 6 x 2
## department n
## <fct> <int>
## 1 Marketing 238
## 2 Sales 252
## 3 Research 293
## 4 Product Development 178
## 5 IT and Analytics 399
## 6 Finance and Operations 110
Trong trường hợp chúng ta muốn sắp xếp theo giá trị giảm dần thì làm như sau
# Thống kê và sắp xếp giảm dần
%>%
employee_data count(department, sort = TRUE)
## # A tibble: 6 x 2
## department n
## <fct> <int>
## 1 IT and Analytics 399
## 2 Research 293
## 3 Sales 252
## 4 Marketing 238
## 5 Product Development 178
## 6 Finance and Operations 110
Hoặc thêm tên cho biến số lượng thay vì hiển thị là n
%>%
employee_data count(department, sort = TRUE, name = "number_of_employees")
## # A tibble: 6 x 2
## department number_of_employees
## <fct> <int>
## 1 IT and Analytics 399
## 2 Research 293
## 3 Sales 252
## 4 Marketing 238
## 5 Product Development 178
## 6 Finance and Operations 110
Hàm count() cũng cho phép truyền thêm tổ hợp đối số vào hàm để đưa ra thông tin phân loại hữu ích hơn, ví dụ: Thống kê số lượng nhân viên của từng phòng ban và theo tình trạng làm việc:
%>%
employee_data count(left_company, department, name = 'number_of_employees')
## # A tibble: 12 x 3
## left_company department number_of_employees
## <fct> <fct> <int>
## 1 No Marketing 198
## 2 No Sales 175
## 3 No Research 284
## 4 No Product Development 128
## 5 No IT and Analytics 369
## 6 No Finance and Operations 79
## 7 Yes Marketing 40
## 8 Yes Sales 77
## 9 Yes Research 9
## 10 Yes Product Development 50
## 11 Yes IT and Analytics 30
## 12 Yes Finance and Operations 31
%>% count(left_company, department, name = 'number_of_employees') %>%
employee_data arrange(department, left_company)
## # A tibble: 12 x 3
## left_company department number_of_employees
## <fct> <fct> <int>
## 1 No Marketing 198
## 2 Yes Marketing 40
## 3 No Sales 175
## 4 Yes Sales 77
## 5 No Research 284
## 6 Yes Research 9
## 7 No Product Development 128
## 8 Yes Product Development 50
## 9 No IT and Analytics 369
## 10 Yes IT and Analytics 30
## 11 No Finance and Operations 79
## 12 Yes Finance and Operations 31
Câu hỏi tiếp theo đặt ra như sau: Số lượng nhân viên hài lòng với công việc của mình là bao nhiêu, theo từng cấp độ, khoảng cách của họ từ nhà tới công sở?
%>% group_by(job_satisfaction) %>%
employee_data summarise(number_of_employees = n(),
avg_miles = mean(miles_from_home))
## # A tibble: 4 x 3
## job_satisfaction number_of_employees avg_miles
## <fct> <int> <dbl>
## 1 Low 289 9.19
## 2 Medium 280 9.10
## 3 High 442 9.42
## 4 Very High 459 9.03
%>%
employee_data count(job_satisfaction, name = 'number_of_employees')
## # A tibble: 4 x 2
## job_satisfaction number_of_employees
## <fct> <int>
## 1 Low 289
## 2 Medium 280
## 3 High 442
## 4 Very High 459
Một điều cần chú ý khi sử dụng hàm group_by() đó là khi chúng ta muốn thực hiện các phương pháp thống kê hoặc thêm biến theo nhóm, theo các biến phân loại, tuy nhiên khi chúng ta muốn sử dụng các kết quả sau khi thu được cho toàn bộ hàng dữ liệu thì sẽ xảy ra lỗi vì khi đó R sẽ tính toán các giá trị cho từng dữ liệu nhóm phân biệt. Để tránh hiện tượng này xảy ra, thông thường chúng ta cần ungroup() sau khi thực hiện thống kê nhóm. Câu hỏi cụ thể trong trường hợp này là: Hãy tính tỷ lệ % của tổng số nhân viên theo chức vụ cụ thể so với toàn thể nhân viên của công ty.
%>% group_by(left_company, job_level) %>%
employee_data summarise(employees = n()) %>%
ungroup() %>%
mutate(percent_of_total_employees = 100*(employees/sum(employees)))
## `summarise()` has grouped output by 'left_company'. You can override using the
## `.groups` argument.
## # A tibble: 10 x 4
## left_company job_level employees percent_of_total_employees
## <fct> <fct> <int> <dbl>
## 1 No Associate 113 7.69
## 2 No Manager 251 17.1
## 3 No Senior Manager 447 30.4
## 4 No Director 303 20.6
## 5 No Vice President 119 8.10
## 6 Yes Associate 72 4.90
## 7 Yes Manager 93 6.33
## 8 Yes Senior Manager 29 1.97
## 9 Yes Director 28 1.90
## 10 Yes Vice President 15 1.02
Các giá trị ngoại lệ (distinct values)
Sử dụng hàm n_distinct() để đếm ra các giá trị mang tính duy nhất (unique) của biến. Giả sử trong 1470 quan sát phía trên, muốn đếm số lượng phòng ban chức năng phân biệt, làm như sau:
%>%
employee_data summarise(number_of_departments = n_distinct(department))
## # A tibble: 1 x 1
## number_of_departments
## <int>
## 1 6
Kết quả trả về là 6, tức là có 6 bộ phận chức năng riêng biệt.
Xếp hạng dữ liệu với top_n()
Hàm top_n() cho biết kết quả trả về các giá trị cao nhất của quan sát trong tập dữ liệu theo biến được lựa chọn. Ví dụ: Hãy liệt kê ra top 5 người có lương cao nhất trong tập dữ liệu
# Liệt kê ra top 5 người có lương cao nhất
%>%
employee_data top_n(5, salary)
## # A tibble: 5 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 No IT and Analytics Vice Presid~ 2.09e5 51 Frequently
## 2 Yes Finance and Ope~ Vice Presid~ 2.05e5 66 Rarely
## 3 No Finance and Ope~ Vice Presid~ 2.12e5 49 Frequently
## 4 Yes Marketing Vice Presid~ 2.07e5 62 Rarely
## 5 Yes IT and Analytics Vice Presid~ 2.12e5 60 Frequently
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
Sử dụng hàm trượt slice
Hàm trượt slice() cho phép lấy dữ liệu theo index cụ thể của quan sát từng dòng dữ liệu. Ví dụ: Lấy ra thông tin của hàng thứ 25 đến 30
%>% slice(25:30) employee_data
## # A tibble: 6 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Marketing Director 108649. 54 Rarely
## 2 No Marketing Manager 62391. 51 Rarely
## 3 Yes Research Director 119443. 62 Frequently
## 4 No Sales Senior Manager 84021. 41 Rarely
## 5 No Research Director 116974. 49 Rarely
## 6 No Marketing Associate 37230. 51 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
# Lấy dữ liệu đơn lẻ, dòng 1, dòng 200 và dòng 1002
%>%
employee_data slice(1, 200, 1002)
## # A tibble: 3 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Director 1.19e5 56 Rarely
## 2 No Finance and Operat~ Director 1.18e5 54 Rarely
## 3 No Sales Director 1.19e5 50 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
Sử dụng thay thế cho top_n(). Liệt kê ra 3 nhân viên có số thời gian công tác lâu năm nhất
%>%
employee_data arrange(desc(yrs_at_company)) %>%
slice(1:3)
## # A tibble: 3 x 13
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Sales Associate 37529. 60 Rarely
## 2 No Sales Manager 72984. 46 Rarely
## 3 No IT and Analytics Director 117306. 49 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
Hàm top_n() và hàm slice() khá hữu ích tỏng trường hợp chúng ta muốn tạo tập dữ liệu con để phân tích và đọc kết quả, ví dụ: hãy liệt kê ra theo từng phòng ban chức năng, 2 nhân viên có lương cao nhất.
%>%
employee_data group_by(department) %>%
top_n(2, salary)
## # A tibble: 12 x 13
## # Groups: department [6]
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 No IT and Analytics Vice Presi~ 2.09e5 51 Frequently
## 2 No Marketing Vice Presi~ 2.03e5 43 None
## 3 Yes Finance and Ope~ Vice Presi~ 2.05e5 66 Rarely
## 4 No Product Develop~ Vice Presi~ 1.95e5 45 Rarely
## 5 No Research Vice Presi~ 2.02e5 53 Rarely
## 6 Yes Product Develop~ Vice Presi~ 1.95e5 57 Rarely
## 7 Yes Sales Vice Presi~ 1.96e5 58 Rarely
## 8 No Finance and Ope~ Vice Presi~ 2.12e5 49 Frequently
## 9 No Research Vice Presi~ 2.04e5 49 Rarely
## 10 No Sales Vice Presi~ 1.98e5 52 Rarely
## 11 Yes Marketing Vice Presi~ 2.07e5 62 Rarely
## 12 Yes IT and Analytics Vice Presi~ 2.12e5 60 Frequently
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
Để hình dung kết quả trên một cách dễ hiểu hơn, sử dụng sắp xếp lại lương
%>% group_by(department) %>%
employee_data top_n(2, salary) %>%
arrange(department, desc(salary))
## # A tibble: 12 x 13
## # Groups: department [6]
## left_company department job_level salary weekly_hours business_travel
## <fct> <fct> <fct> <dbl> <dbl> <fct>
## 1 Yes Marketing Vice Presi~ 2.07e5 62 Rarely
## 2 No Marketing Vice Presi~ 2.03e5 43 None
## 3 No Sales Vice Presi~ 1.98e5 52 Rarely
## 4 Yes Sales Vice Presi~ 1.96e5 58 Rarely
## 5 No Research Vice Presi~ 2.04e5 49 Rarely
## 6 No Research Vice Presi~ 2.02e5 53 Rarely
## 7 No Product Develop~ Vice Presi~ 1.95e5 45 Rarely
## 8 Yes Product Develop~ Vice Presi~ 1.95e5 57 Rarely
## 9 Yes IT and Analytics Vice Presi~ 2.12e5 60 Frequently
## 10 No IT and Analytics Vice Presi~ 2.09e5 51 Frequently
## 11 No Finance and Ope~ Vice Presi~ 2.12e5 49 Frequently
## 12 Yes Finance and Ope~ Vice Presi~ 2.05e5 66 Rarely
## # ... with 7 more variables: yrs_at_company <int>, yrs_since_promotion <int>,
## # previous_companies <dbl>, job_satisfaction <fct>, performance_rating <fct>,
## # marital_status <fct>, miles_from_home <int>
Thiết lập chỉ số logic
Các thuộc tính đặc biệt của vectơ logic
Hãy tưởng tượng chúng ta có dữ liệu từ một cuộc khảo sát mà chúng ta đã thực hiện gần đây, trong đó 7 người đã trả lời và cung cấp thông tin về tuổi của họ. Dữ liệu này được lưu trữ trong vector tuổi bên dưới.
Giẳ sử chúng ta muốn biết số người từ 30 tuổi trở lên và bao nhiêu phần trăm trong tổng số người được hỏi đại diện cho nhóm này? Khi đó chúng ta sử dụng phép so sánh theo index, để trả lời cho câu hỏi trên, sử dụng kết hợp lấy tập dữ liệu con theo véc tơ logic. Hàm sum() trả về kết quả số người trên 30 tuổi, hàm mean() trả về kết quả trung bình số người này chiếm % tổng số người được hỏi.
<- c(23, 31, 27, 41, 54, 34, 25)
age age
## [1] 23 31 27 41 54 34 25
# Kết quả trả về véc tơ logic có điều kiện
>= 30 age
## [1] FALSE TRUE FALSE TRUE TRUE TRUE FALSE
sum(age >=30)
## [1] 4
mean(age >=30)
## [1] 0.5714286
Như vậy là có 4 người có tuổi trên 30 và số người này chiếm 57% số người được hỏi khảo sát.
Áp dụng vào tập dữ liệu về phân bổ nhân viên trong công ty. Câu hỏi đặt ra là: Có bao nhiêu người trong công ty có lương dưới 60.000$ trong từng lĩnh vực phòng ban và số lượng người này chiếm bao nhiêu % trong từng phòng ban đó?
%>% group_by(department) %>%
employee_data summarise(employees = n(),
employees_less_60 = sum(salary < 60000),
employees_less_60_prop = mean(salary < 60000))
## # A tibble: 6 x 4
## department employees employees_less_60 employees_less_60_prop
## <fct> <int> <int> <dbl>
## 1 Marketing 238 31 0.130
## 2 Sales 252 46 0.183
## 3 Research 293 23 0.0785
## 4 Product Development 178 28 0.157
## 5 IT and Analytics 399 57 0.143
## 6 Finance and Operations 110 16 0.145
Cuối cùng, chúng ta cùng xét một ví dụ đơn giản như sau về một survey khảo sát về thông tin của nhân viên
<- tibble(age = c(26, 31, 28, 42, 31, 37, 51, 29),
survey job_function = c('Biotechnology', 'Analytics', 'Machine Learning',
'Marketing','Biotechnology', 'Machine Learning',
'Analytics', 'Biotechnology'),
job_industry = c('Healthcare', 'Healthcare', 'Financial Services',
'Retail', 'Non-Profit', 'Education',
'Retail', 'Healthcare'),
job_level = c('Entry', 'Mid', 'Mid', 'Senior', 'Mid',
'Mid', 'Senior', 'Mid'),
salary = c(75500, 87600, 97000, 92000, 89000,
108500, 121000, 94000))
survey
## # A tibble: 8 x 5
## age job_function job_industry job_level salary
## <dbl> <chr> <chr> <chr> <dbl>
## 1 26 Biotechnology Healthcare Entry 75500
## 2 31 Analytics Healthcare Mid 87600
## 3 28 Machine Learning Financial Services Mid 97000
## 4 42 Marketing Retail Senior 92000
## 5 31 Biotechnology Non-Profit Mid 89000
## 6 37 Machine Learning Education Mid 108500
## 7 51 Analytics Retail Senior 121000
## 8 29 Biotechnology Healthcare Mid 94000
Trong nhiều trường hợp, chúng ta cần mã hóa (recoding) lại các biến là biến phân loại theo yêu cầu của bài toán, khi đó chúng ta sử dụng hàm recode().
# Thay thế giá trị Analytics bằng Data Science và
# Machine Learning bằng Data Science
recode(survey$job_function,
'Analytics' = 'Data Science',
'Machine Learning' = 'Data Science')
## [1] "Biotechnology" "Data Science" "Data Science" "Marketing"
## [5] "Biotechnology" "Data Science" "Data Science" "Biotechnology"
# Sử dụng recode_factor cho biến factor
%>%
survey mutate(job_function_chr = recode(job_function,
'Analytics' = 'Data Science',
'Machine Learning' = 'Data Science'),
job_function_fct = recode_factor(job_function,
'Analytics' = 'Data Science',
'Machine Learning' = 'Data Science'))
## # A tibble: 8 x 7
## age job_function job_industry job_level salary job_function_chr
## <dbl> <chr> <chr> <chr> <dbl> <chr>
## 1 26 Biotechnology Healthcare Entry 75500 Biotechnology
## 2 31 Analytics Healthcare Mid 87600 Data Science
## 3 28 Machine Learning Financial Services Mid 97000 Data Science
## 4 42 Marketing Retail Senior 92000 Marketing
## 5 31 Biotechnology Non-Profit Mid 89000 Biotechnology
## 6 37 Machine Learning Education Mid 108500 Data Science
## 7 51 Analytics Retail Senior 121000 Data Science
## 8 29 Biotechnology Healthcare Mid 94000 Biotechnology
## # ... with 1 more variable: job_function_fct <fct>
Tạo biến mới với case_when()
Hàm case_when () trong gói dplyr đặc biệt hữu ích khi chúng ta cần tạo một biến mới dựa trên sự kết hợp phức tạp của các biến hiện có trong tập dữ liệu. Hàm case_when () nhận một chuỗi các công thức hai vế. Bên vế trái xác định giá trị nào phù hợp với trường hợp này và bên vế phải cung cấp giá trị thay thế.
Cú pháp chung là điều kiện logic ~ giá trị thay thế, trong đó điều kiện logic có thể liên quan đến nhiều biến từ một khung dữ liệu. Dãy kết thúc bằng giá trị TRUE ~ cho tất cả các trường hợp khác.
Ví dụ:
# tạo tập dữ liệu survey_updated với biến ds_biotech_30 mới
<- survey %>%
survey_updated mutate(ds_biotech_30 = case_when(age >= 30 & job_function %in% c('Analytics', 'Machine Learning') ~ 'Data Science, 30+', age >= 30 & job_function == "Biotechnology" ~ "Biotechnology, 30+",
TRUE ~ 'Other'))
survey_updated
## # A tibble: 8 x 6
## age job_function job_industry job_level salary ds_biotech_30
## <dbl> <chr> <chr> <chr> <dbl> <chr>
## 1 26 Biotechnology Healthcare Entry 75500 Other
## 2 31 Analytics Healthcare Mid 87600 Data Science, 30+
## 3 28 Machine Learning Financial Services Mid 97000 Other
## 4 42 Marketing Retail Senior 92000 Other
## 5 31 Biotechnology Non-Profit Mid 89000 Biotechnology, 30+
## 6 37 Machine Learning Education Mid 108500 Data Science, 30+
## 7 51 Analytics Retail Senior 121000 Data Science, 30+
## 8 29 Biotechnology Healthcare Mid 94000 Other
Tạo biến nhóm phân loại (Binning Numeric Variables)
Chia một biến dữ liệu ở dạng số thành các nhóm (biến phân loại) là một dạng điển hình trong tạo biến nhóm phân loại trong thống kê (phương pháp chia khoảng). Trong nội dung này, chúng ta sử dụng hàm cut(). Bài toán đặt ra là có các mức tuổi khác nhau và đưa dữ liệu từ bảng survey trên cho các đối tượng về biến phân loại.
# Dữ liệu biến tuổi ban đầu
$age survey
## [1] 26 31 28 42 31 37 51 29
cut(x = survey$age,
breaks = c(-Inf, 24, 35, Inf), # Lấy khoảng dữ liệu từ 24-35
labels = c("Less than 25", "25 - 35", "36 and older"), # Các mức tuổi
right = TRUE) # Cho phép lấy khoảng đóng bên phải
## [1] 25 - 35 25 - 35 25 - 35 36 and older 25 - 35
## [6] 36 and older 36 and older 25 - 35
## Levels: Less than 25 25 - 35 36 and older
Sử dụng pipe và dplyr
%>%
survey mutate(age_category = cut(age,
breaks = c(-Inf, 24, 35, Inf),
labels = c("Less than 25", "25 - 35", "36 and older"),
right = TRUE)) %>%
select(age, age_category)
## # A tibble: 8 x 2
## age age_category
## <dbl> <fct>
## 1 26 25 - 35
## 2 31 25 - 35
## 3 28 25 - 35
## 4 42 36 and older
## 5 31 25 - 35
## 6 37 36 and older
## 7 51 36 and older
## 8 29 25 - 35
Chia khoảng tự động - Auto binning
Để chia khoảng tự động, có 3 hàm hữu ích có thể liệt kê, đó là:
cut_interval () tạo n nhóm có khoảng bằng nhau
cut_number () tạo thành n nhóm có (xấp xỉ) số lượng quan sát bằng nhau
cut_width () tạo các nhóm có chiều rộng nhất định
# Dữ liệu gốc
$age survey
## [1] 26 31 28 42 31 37 51 29
# Chia thành 3 khoảng đều nhau
<- cut_interval(survey$age, n = 3)
age_interval age_interval
## [1] [26,34.3] [26,34.3] [26,34.3] (34.3,42.7] [26,34.3] (34.3,42.7]
## [7] (42.7,51] [26,34.3]
## Levels: [26,34.3] (34.3,42.7] (42.7,51]
summary(age_interval)
## [26,34.3] (34.3,42.7] (42.7,51]
## 5 2 1
Sử dụng cut_number() chia dữ liệu thành các khoảng có số quan sát bằng nhau
# cut_number
<- cut_number(survey$age, n = 3)
age_number age_number
## [1] [26,29.7] (29.7,35] [26,29.7] (35,51] (29.7,35] (35,51] (35,51]
## [8] [26,29.7]
## Levels: [26,29.7] (29.7,35] (35,51]
summary(age_number)
## [26,29.7] (29.7,35] (35,51]
## 3 2 3
Sử dụng cut_width() để cắt theo chiều dài của dữ liệu
$age survey
## [1] 26 31 28 42 31 37 51 29
<- cut_width(survey$age, width = 10, boundary = 0)
age_width age_width
## [1] [20,30] (30,40] [20,30] (40,50] (30,40] (30,40] (50,60] [20,30]
## Levels: [20,30] (30,40] (40,50] (50,60]
summary(age_width)
## [20,30] (30,40] (40,50] (50,60]
## 3 3 1 1
Ví dụ thực hành với cut()
Hãy sử dụng hàm cut_width() để hoàn thành quy trình phân tích dữ liệu sau với dplyr
Bắt đầu với dữ liệu employ_data
Tạo biến mile_category chứa các giá trị mile_from_home theo gia số (increment) 5 dặm
Nhóm biểu mẫu theo left_company và mile_category
Đếm số lượng nhân viên thuộc mỗi nhóm
%>%
employee_data mutate(miles_category = cut_width(miles_from_home,
width = 5, boundary = 0)) %>%
group_by(left_company, miles_category) %>%
summarise(employees = n())
## `summarise()` has grouped output by 'left_company'. You can override using the
## `.groups` argument.
## # A tibble: 12 x 3
## # Groups: left_company [2]
## left_company miles_category employees
## <fct> <fct> <int>
## 1 No [0,5] 545
## 2 No (5,10] 337
## 3 No (10,15] 90
## 4 No (15,20] 102
## 5 No (20,25] 85
## 6 No (25,30] 74
## 7 Yes [0,5] 87
## 8 Yes (5,10] 57
## 9 Yes (10,15] 25
## 10 Yes (15,20] 23
## 11 Yes (20,25] 32
## 12 Yes (25,30] 13
Department of Computer Sciences and Engineering, Faculty of Information Technology, Thai Nguyen University of Information Technology and Communication, tqquy@ictu.edu.vn↩︎
Head of Department of Computer Sciences and Engineering, Faculty of Information Technology, Thai Nguyen University of Information Technology and Communication, nddung@ictu.edu.vn↩︎
Advanced class of Information Technology K18, Thai Nguyen University of Information Technology and Communication, maiduchuy321@mgmail.com↩︎
Advanced class of Information Technology K18, Thai Nguyen University of Information Technology and Communication, DTC195480201clc0015@ictu.edu.vn↩︎