Trước hết đọc bộ dữ liệu THPT 2018 Quoc gia.csv vào R và đặt tên cho Data Frame này là raw_data
# Load library
library(readr)
read.csv("D:\\DATA_SCIENCE\\R_COURSE_CASED\\data_day12\\THPT 2018 Quoc gia.csv") -> raw_dataConvert cột biến SoBD (thông tin số báo danh của thí sinh) về character
## int [1:744396] 18010226 18010229 18010232 18010242 18010247 18010252 18010259 18010262 18010265 18010268 ...
# Convert into character
raw_data %>%
mutate(SoBD = as.character(SoBD)) -> raw_data
# Check if converting works
str(raw_data$SoBD)## chr [1:744396] "18010226" "18010229" "18010232" "18010242" "18010247" ...
Sử dụng str_count() để tạo ra soluongkt phản ánh thông tin về số lượng kí tự được sử dụng cho Số Báo Danh.
# Load library
library(stringr)
raw_data %>%
mutate(soluongkt = str_count(SoBD)) -> raw_data
head(raw_data)## ID SoBD Math Viet English Physics Chemistry Biology History Geography
## 1 1 18010226 3.0 3.75 3.0 NA NA NA 3.0 6.50
## 2 2 18010229 8.8 7.50 9.0 NA NA NA 6.0 9.00
## 3 3 18010232 6.0 5.50 4.0 5.75 5.5 5.00 NA NA
## 4 4 18010242 3.4 5.75 2.6 NA NA NA 3.5 4.75
## 5 5 18010247 3.8 6.75 3.0 NA NA NA 3.5 6.25
## 6 6 18010252 5.0 6.50 2.2 2.00 3.5 4.25 NA NA
## GDCD X KhoiA KhoiB KhoiC KhoiD KhoiA1 soluongkt
## 1 8.25 NA NA NA 13.25 9.75 NA 8
## 2 8.25 NA NA NA 22.50 25.3 NA 8
## 3 NA NA 17.25 16.50 NA 15.5 15.75 8
## 4 7.25 NA NA NA 14.00 11.75 NA 8
## 5 8.00 NA NA NA 16.50 13.55 NA 8
## 6 NA NA 10.50 12.75 NA 13.7 9.20 8
Có bao nhiêu số báo danh có 8 kí tự
## soluongkt n
## 1 7 152357
## 2 8 592039
## # A tibble: 2 x 2
## # Groups: soluongkt [2]
## soluongkt n
## <int> <int>
## 1 7 152357
## 2 8 592039
Thêm chữ số 0 vào trước nhóm số báo danh chỉ có 7 kí tự để tạo thành cột biến mới có tên là SoBD_new
raw_data %>%
mutate(SoBD_new = case_when (
soluongkt == 7 ~ paste0("0", SoBD),
TRUE ~ SoBD
)) -> raw_data
# Alternatively, use function str_c [soluongkt == 7 ~ str_c("0",SoBD)]
raw_data %>%
mutate(SoBD_new = case_when (
soluongkt == 7 ~ str_c("0",SoBD),
TRUE ~ SoBD
)) -> raw_data
# Check if all SoBD is now consisting of 8 characters
raw_data$SoBD_new %>% str_count() %>% length()## [1] 744396
Lấy thông tin về mã tỉnh của kì thi tốt nghiệp THPT 2018
# Load library
library(rvest)
matinh_link <- "https://thuvienphapluat.vn/cong-van/Giao-duc/Cong-van-417-BGDDT-KTKDCLGD-huong-dan-thuc-hien-Quy-che-thi-trung-hoc-pho-thong-quoc-gia-2017-339311.aspx"
matinh_xpath <- '//*[@id="divContentDoc"]/div/div/div/table[7]'
# Get data table from the websource
matinh_link %>%
read_html() %>%
html_nodes(xpath = matinh_xpath) %>%
html_table %>%
.[[1]] %>%
mutate_all(function(x) {stri_trans_general(x, "Latin-ASCII")}) %>% # Convert font
slice(-1) -> df_matinh # First row is redundant
# Rename columns and select only the first two because they are resemble to the last two
# Store this data in df_matinh
df_matinh %>%
mutate(code = X1, province = substring(X2,9)) %>%
select(code, province) -> df_matinh
head(df_matinh)## code province
## 1 01 Ha Noi
## 2 02 TP. Ho Chi Minh
## 3 03 Hai Phong
## 4 04 Da Nang
## 5 05 Ha Giang
## 6 06 Cao Bang
Tạo ra một cột biến mới có tên province cho raw_data rồi báo cáo con số về số lượng thí sinh tham dự kì thi theo chiều giảm dần
# Extract province's code from SoBD
raw_data %>%
mutate(code = substr(SoBD_new, 1, 2)) -> raw_data
# Join raw_data with df_matinh by province's code
full_join(raw_data, df_matinh, by = "code") -> raw_data
# Count number of students in each province and sort in descending order
# Store this result in df_soluong_theotinh
raw_data %>%
group_by(province) %>%
count() %>%
arrange(-n) -> df_soluong_theotinh
df_soluong_theotinh## # A tibble: 64 x 2
## # Groups: province [64]
## province n
## <chr> <int>
## 1 TP. Ho Chi Minh 78321
## 2 Ha Noi 38099
## 3 Dong Nai 28651
## 4 Dak Lak 22035
## 5 Thai Binh 21435
## 6 Hai Duong 19973
## 7 Bac Giang 19612
## 8 Binh Dinh 17785
## 9 Quang Nam 17532
## 10 Ha Tinh 16330
## # ... with 54 more rows
# Comment: Some provinces reported only 1. Indeed these are provinces whose data is missing.
check <- is.na(raw_data$SoBD)
sum(check)## [1] 5
## [1] "Son La" "Quang Ninh" "Nghe An"
## [4] "An Giang" "truong - Bo Quoc phong"
Chỉ xét những thí sinh thi khối A của kì thi này. Tính toán tỉ lệ thí sinh có tổng điểm thi ba môn lớn hơn hoặc bằng 25 cho các tỉnh rồi sắp xếp tỉ lệ này theo chiều giảm dần. Ở đây định nghĩa tỉ lệ thí sinh có tổng điểm thi ba môn lớn hơn hoặc bằng 25” bằng số lượng thí sinh có tổng điểm ba môn lớn hơn hoặc bằng 25 chia cho tổng số thi sinh tham dự kì thi khối A của từng tỉnh.
# Filter students taking KhoiA only
raw_data %>%
filter(!is.na(KhoiA)) %>%
mutate(over25 = case_when(KhoiA >= 25 ~ 1, TRUE ~ 0)) -> df_khoiA
# Count numbers of over25 and under25 in each province
df_khoiA %>%
group_by(province, over25) %>%
count() -> df_over25
# Split those under25 in separate dataframe
df_over25 %>%
filter(over25 == 0) %>%
rename(n_under = n) -> df_under25
# Split those over25 in another dataframe
df_over25 %>%
filter(over25 == 1) -> df_over25
# Join these two dataframes back by province
full_join(df_over25, df_under25, by = "province") -> df_rate
# Compute the rate of over25 for each province and sort in descending order
df_rate %>%
mutate(rate = n/(n + n_under)*100) %>%
arrange(-rate) -> df_rate
# Report results
df_rate## # A tibble: 59 x 6
## # Groups: province [59]
## province over25.x n over25.y n_under rate
## <chr> <dbl> <int> <dbl> <int> <dbl>
## 1 Ha Giang 1 27 0 554 4.65
## 2 Bac Ninh 1 47 0 5174 0.900
## 3 Thai Binh 1 91 0 10058 0.897
## 4 Ninh Binh 1 31 0 3483 0.882
## 5 Hoa Binh 1 20 0 2336 0.849
## 6 Thanh Hoa 1 44 0 5453 0.800
## 7 Vinh Phuc 1 30 0 4040 0.737
## 8 Hai Phong 1 14 0 1947 0.714
## 9 Nam Dinh 1 18 0 2697 0.663
## 10 Bac Giang 1 33 0 5031 0.652
## # ... with 49 more rows
Viết một hàm có tên xep_loai nhận input, kí hiệu x, là một số thực không âm nằm trong đoạn từ 0 đến 10 và trả về kết quả theo định nghĩa sau:
# Write "xep_loai" function
xep_loai <- function(x) {
y <- case_when(x >= 9 ~ "Group A",
x >= 8 & x < 9 ~ "Group B",
x >= 7 & x < 8 ~ "Group C",
x >= 6 & x < 7 ~ "Group D",
x >= 5 & x < 6 ~ "Group E",
TRUE ~ "Group F"
)
return(y)
}Sử dụng hàm này để: a. Chỉ xét các thí sinh thi khối A. Tính toán tỉ lệ thí sinh có điểm thi môn Toán thuộc nhóm GroupA cho các tỉnh.
# Count number of groupA/not GroupA students in Math in each province
df_khoiA %>%
mutate(rank_math = xep_loai(Math)) %>%
mutate(group_A = case_when(rank_math == "Group A" ~ "Group_A", TRUE ~ "Not_Group_A")) %>%
group_by(province, group_A) %>%
count() -> df_groupA
# Convert df_groupA into wide form
library(tidyr)
df_groupA %>%
pivot_wider(names_from = group_A, values_from = n) -> df_groupA_wide
# Calculate the rate and sort in descending order
df_groupA_wide %>%
mutate(Group_A = replace_na(Group_A,0)) %>%
mutate(rate_groupA = Group_A/(Group_A + Not_Group_A)*100) %>%
arrange(-rate_groupA) -> df_groupA_wide
# Report results
df_groupA_wide## # A tibble: 59 x 4
## # Groups: province [59]
## province Group_A Not_Group_A rate_groupA
## <chr> <dbl> <int> <dbl>
## 1 Ha Giang 26 555 4.48
## 2 Hoa Binh 20 2336 0.849
## 3 Phu Tho 22 3140 0.696
## 4 Ha Noi 63 15800 0.397
## 5 Hai Phong 6 1955 0.306
## 6 Thanh Hoa 16 5481 0.291
## 7 Hung Yen 15 5257 0.285
## 8 Dien Bien 2 767 0.260
## 9 Ninh Binh 9 3505 0.256
## 10 Lang Son 3 1180 0.254
## # ... with 49 more rows
# Filter Khoi B students only
raw_data %>%
filter(!is.na(KhoiB)) %>%
filter(!is.na(Biology)) -> df_khoiB
# Compute number of student in Group A for Biology in each province
# Store this result in df_bio
df_khoiB %>%
mutate(rank_bio = xep_loai(Biology)) %>%
mutate(groupA_bio = case_when(rank_bio == "Group A" ~ "Group_A_Bio",
TRUE ~ "Not_Group_A_Bio")) %>%
group_by(province, groupA_bio) %>%
count() -> df_bio
# Transpose into wide form
df_bio %>%
pivot_wider(names_from = groupA_bio, values_from = n) -> df_groupA_bio
# Compute the rate of groupA students for biology in each province
df_groupA_bio %>%
mutate(Group_A_Bio = replace_na(Group_A_Bio)) %>%
mutate(rate_groupA_bio = Group_A_Bio/(Group_A_Bio + Not_Group_A_Bio)*100) %>%
arrange(-rate_groupA_bio) -> df_groupA_bio
# Report results
df_groupA_bio## # A tibble: 59 x 4
## # Groups: province [59]
## province Group_A_Bio Not_Group_A_Bio rate_groupA_bio
## <chr> <int> <int> <dbl>
## 1 Ha Giang 3 567 0.526
## 2 Dien Bien 4 781 0.510
## 3 Kon Tum 6 1592 0.375
## 4 Ha Tinh 15 5052 0.296
## 5 Bac Kan 1 346 0.288
## 6 Hai Duong 14 7367 0.190
## 7 Phu Tho 5 3150 0.158
## 8 Lai Chau 1 653 0.153
## 9 Ha Noi 23 15692 0.146
## 10 Tra Vinh 4 2805 0.142
## # ... with 49 more rows
Xem Bar Plot trình bày ở trang 26 của báo cáo PCI2018 tại http://pci2018.pcivietnam.vn/uploads/2019/ho-so-63-tinh-vie.pdf rồi trả lời các câu hỏi sau:
Bar Plot còn thiếu sót gì?
Sử dụng dữ liệu du-lieu-pci-2018.xlsx cung cấp bởi http://pci2018.pcivietnam.vn/ để tạo Bar Plot theo bố cục và cách trình bày tương tự như Bar Plot thuộc trang 26 của báo cáo này
library(readxl)
# Load data
read_excel("D:\\DATA_SCIENCE\\R_COURSE_CASED\\Lecture_2\\du_lieu_pci_2018.xlsx",
range = "A2:C64",
col_names = FALSE)-> df_pci
# Rename columns
df_pci %>%
rename(province = ...1,
rank = ...2,
pci_score = ...3) -> df_pci
# Processing data
# Categorize pci_score into groups using standard deviation from the mean
df_pci %>%
mutate(mean = mean(pci_score)) %>%
mutate(sd = sd(pci_score)) %>%
mutate(category = case_when(pci_score >= mean + 2*sd ~ "Rất tốt",
pci_score < mean + 2*sd & pci_score >= mean + sd ~ "Tốt",
pci_score < mean + sd & pci_score >= mean ~ "Khá",
pci_score < mean & pci_score >= mean - sd ~ "Trung bình",
pci_score < mean - sd & pci_score >= mean - 2*sd ~ "Tương đối thấp",
TRUE ~ "Thấp")) %>%
mutate(pci_score = round(pci_score, digits = 2)) -> df_pci
# Arrange pci_score in descending order and factorize province
df_pci %>%
arrange(pci_score) %>%
mutate(province_ft = factor(province, levels = province)) %>%
mutate(color = case_when(category == "Rất tốt" ~ "#7D3C98",
category == "Tốt" ~ "#034EA2",
category == "Khá" ~ "#4792CF",
category == "Trung bình" ~ "#8ED8F8",
category == "Tương đối thấp" ~ "#ABEBC6",
category == "Thấp" ~ "#FADBD8"
)) -> df_pci
# Draw bar chart
library(dplyr)
library(ggplot2)
# Color code
# https://html-color-codes.info/colors-from-image/
df_pci %>%
ggplot(aes(x = pci_score, y = province_ft)) +
geom_col(fill = df_pci$color, color = "white", width = 0.6) +
labs(title = "Figure 1: Vietnam Provincial Competitiveness Index (CPI) 2018",
x = NULL, y = NULL,
caption = "Source: http://pci2018.pcivietnam.vn/") +
theme(axis.text.y = element_text(size = 8)) +
geom_text(aes(label = pci_score), size = 2, hjust = -0.3)
Comments on improvements of this chart: