CALL PACKAGES
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.3.2
## Warning: package 'readr' was built under R version 4.3.2
## Warning: package 'forcats' was built under R version 4.3.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.3 ✔ tibble 3.2.1
## ✔ lubridate 1.9.2 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readxl)
library(tmap)
## Warning: package 'tmap' was built under R version 4.3.3
## Breaking News: tmap 3.x is retiring. Please test v4, e.g. with
## remotes::install_github('r-tmap/tmap')
LOAD DATA
jobs_in_data = read_excel("D:/DS in Economics & Business/jobs_in_data.xlsx")
View(jobs_in_data)
attach(jobs_in_data)
str(jobs_in_data)
## tibble [9,355 × 12] (S3: tbl_df/tbl/data.frame)
## $ work_year : num [1:9355] 2023 2023 2023 2023 2023 ...
## $ job_title : chr [1:9355] "Data DevOps Engineer" "Data Architect" "Data Architect" "Data Scientist" ...
## $ job_category : chr [1:9355] "Data Engineering" "Data Architecture and Modeling" "Data Architecture and Modeling" "Data Science and Research" ...
## $ salary_currency : chr [1:9355] "EUR" "USD" "USD" "USD" ...
## $ salary : num [1:9355] 88000 186000 81800 212000 93300 ...
## $ salary_in_usd : num [1:9355] 95012 186000 81800 212000 93300 ...
## $ employee_residence: chr [1:9355] "Germany" "United States" "United States" "United States" ...
## $ experience_level : chr [1:9355] "Mid-level" "Senior" "Senior" "Senior" ...
## $ employment_type : chr [1:9355] "Full-time" "Full-time" "Full-time" "Full-time" ...
## $ work_setting : chr [1:9355] "Hybrid" "In-person" "In-person" "In-person" ...
## $ company_location : chr [1:9355] "Germany" "United States" "United States" "United States" ...
## $ company_size : chr [1:9355] "L" "M" "M" "M" ...
CHECK DATA
#Kiểm tra xem dữ liệu có tồn tại giá trị NA không
sum(is.na(jobs_in_data))
## [1] 0
#Kiểm tra xem dữ liệu có tồn tại giá trị NULL không
sum(is.null(jobs_in_data))
## [1] 0
#Xem các giá trị của biến job_category
unique(job_category)
## [1] "Data Engineering" "Data Architecture and Modeling"
## [3] "Data Science and Research" "Machine Learning and AI"
## [5] "Data Analysis" "Leadership and Management"
## [7] "BI and Visualization" "Data Quality and Operations"
## [9] "Data Management and Strategy" "Cloud and Database"
#Số lượng việc làm về data trong 4 năm (nhóm theo job_category và work_year)
jobs_in_data %>% group_by(work_year, job_category) %>%
count(job_category)%>%
ggplot(aes(work_year,n))+geom_line(aes(color=job_category))+geom_point(aes(color=job_category)) + labs(title = "Số lượng việc làm về data trong 4 năm", subtitle = "Nhóm theo job_category", x="Năm", y="Frequency")
Từ đây chỉ sử dụng dữ liệu thuộc năm 2023 vì bộ dữ liệu của năm 2020, 2021, 2022 không đủ để trực quan, tuy vậy cũng phần nào cho thấy được số lượng việc làm của nghề data tăng nhanh cùng với sự phát triển của khoa học kỹ thuật
#Tỉ lệ phần trăm của employment_type
jobs_in_data1 = jobs_in_data%>% filter (work_year ==2023)
total_rows = nrow(jobs_in_data1)
jobs_in_data1%>%
count(employment_type) %>%
mutate(prop1 = round(n / total_rows * 100, 3))
Từ đây chỉ sử dụng dữ liệu thuộc năm 2023 và có employment_type = Full-time
#Tỉ lệ phần trăm theo experience_level
jobs_in_data2 = jobs_in_data %>% filter(work_year==2023, employment_type=="Full-time")
total_rows1=nrow(jobs_in_data2)
jobs_in_data2 %>% group_by(experience_level) %>%
count(experience_level) %>%
mutate(percent=round(n/total_rows1 *100,2)) %>%
ggplot(aes(x=experience_level, y=percent, fill=experience_level)) +
geom_bar(stat="identity") + geom_text(aes(label=percent, vjust = -0.3)) + labs(title = "Tỉ lệ % của mỗi cấp độ kinh nghiệm làm việc", x="Experience Level", y="Percentile")
#Tỉ lệ phần trăm theo company_size
jobs_in_data2 %>% group_by(company_size) %>%
count(company_size) %>%
mutate(percent1=round(n/total_rows1 *100,2)) %>%
ggplot(aes(x=company_size, y=percent1, fill=company_size)) +
geom_bar(stat="identity") + geom_text(aes(label=percent1, vjust = -0.3)) +labs(y="Percentile")
Các công ty có nghề data có size vừa là chủ yếu (size M)
#Tỉ lệ phần trăm theo work_setting
jobs_in_data2%>%
count(work_setting) %>%
mutate(prop2 = round(n / total_rows1 * 100, 3))%>%
ggplot(aes(x="", y=round(n / total_rows1 * 100, 3), fill=work_setting)) +
geom_col(width=1, color="white") +
coord_polar(theta="y") +
geom_text(aes(label = paste0(round(n / total_rows1 * 100, 3), "%"), x=1.8),
position=position_stack(vjust=0.5)) +
ggtitle("Percentage of Work Setting") +
theme_void() +
theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
plot.title = element_text(hjust=0.8, size=15)) +
scale_fill_brewer(palette="Blues")+
guides(fill=guide_legend(title = "Work Setting"))
Work setting theo In-person chiếm số lượng lớn, tuy nhiên Remote cũng chiếm số phần trăm khá cao (lên tới 32.406%) => Điều này là hoàn toàn hợp lý khi công nghệ hiện đại hóa như hiện nay thì làm từ xa vẫn đem lại hiệu quả như In-person do có sự tiên tiến về thiết bị, mạng, môi trường,…
#World Map số lượng jobs data trên thế giới dựa trên bộ dữ liệu đã lấy
data(World)
World$company_location = World$name
summary_table_1 = jobs_in_data2 %>%
group_by(company_location) %>%
count(company_location) %>% ungroup()
worldmap = left_join(World, summary_table_1, by="company_location")
ggplot(data = worldmap) + geom_sf(aes(fill=n), color="black")+scale_fill_gradient(low = "#66CCFF", high = "#003366", name = "Number of jobs", labels = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k"))+labs(title = "The number of Jobs", subtitle = "Grouped by Company Location")
Hoa Kỳ chiếm số lượng lớn nhất, tuy nhiên có vẻ số liệu ở đây không đủ vì hiện nay Trung Quốc cũng không hề kém cạnh Hoa Kỳ về số lượng job về data
#Số lượng theo job_category tại US
jobs_in_data2 %>% filter(company_location=="United States") %>%
group_by(job_category) %>%
count(job_category) %>%
ggplot(aes(x=n,y=job_category, fill=job_category))+geom_bar(stat = "identity")+labs(x = "Number of jobs")
Ở Mỹ, Data Science and Research đang chiếm số lượng áp đảo, theo sau đó là Data Engineering và Machine Learning and AI. Số lượng job ít nhất là Cloud and Database rồi đến Data Quality and Operations
jobs_in_data2%>%ggplot(aes(x = salary_in_usd)) +
geom_histogram(aes(y = ..density..),color = '#5c082c', fill ='#F5B0CB', bins=20) +
labs(title = "Histogram for Salary ($)",x = "Salary in USD",y = "Count") +
geom_density(alpha=.2, color="#996666")+
theme_classic() +
theme(
plot.title = element_text(color = "#383335", size = 18, face = "bold"),
plot.subtitle = element_text(color = "#F5B0CB",size = 12, face = "bold"),
plot.caption = element_text(face = "italic"))
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
summary_table2 = jobs_in_data2 %>%
group_by(company_location) %>%
mutate(avg_salary = round(mean(salary_in_usd))) %>%
arrange(desc(avg_salary)) %>%
ungroup()
df_unique = distinct(summary_table2, summary_table2$company_location, .keep_all = TRUE)%>%head(10)
ggplot(df_unique, aes(x = reorder(company_location, -avg_salary), y = avg_salary, fill = company_location)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k")(avg_salary)), vjust = -0.5, size = 3, fontface = "bold") +
labs(title = "Top 10 countries with highest average salaries", subtitle = "",
x = "Company Location",
y = "Average Salary"
) +
theme_minimal() +
guides(fill = "none") +
theme(axis.text.x = element_text(angle = 45, vjust = 0.5, size = 9, color = "black", face ="bold"), axis.text.y = element_blank(), title = element_text(size = 9), legend.title = element_text(size = 12), legend.text = element_text(size = 12))
Top 10 nước có số lương trung bình cao nhất: - Top 1 là Qatar, tuy nhiên sau khi kiểm tra dữ liệu thì thấy bộ dữ liệu khảo sát Qatar chỉ có duy nhất một quan sát nên điều này ảnh hưởng đến việc nhận định Qatar là nước có tiền lương trung bình cao nhất thế giới - Tiếp theo là Australia, US, Japan,…, cho thấy sự triển vọng về việc làm cũng như mức lương ở các nước này dành cho những chuyên gia phát triển hơn
summary_table_3 = jobs_in_data2 %>%
group_by(company_location) %>%
mutate(avg_salary = round(mean(salary_in_usd))) %>% ungroup()
worldmap = left_join(World, summary_table_3, by="company_location")
ggplot(data = worldmap) + geom_sf(aes(fill=avg_salary), color="black")+scale_fill_gradient(low = "#66CCFF", high = "#000055", name = "Avg salary", labels = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k"))+labs(title = "The Average Salary (USD) in thousand (k)", subtitle = "Grouped by Company Location")
Nhóm theo Company Location cũng tương tự như hình vẽ trước, do sự thiếu khảo sát của dữ liệu mà Qatar chỉ có duy nhất 1 quan sát, do vậy màu đậm nhất
BOX-PLOT
#Box-plot của job_category theo salary_in_usd
jobs_in_data2 %>%
group_by(job_category) %>%
ggplot()+geom_boxplot(aes(x = reorder(job_category, salary_in_usd, FUN = median),salary_in_usd))+theme(axis.text.x= element_text(size =8, face = "bold",vjust=0.75,angle = 90))+labs(x="job_category")
#Box-plot của work_setting theo salary_in_usd
jobs_in_data2 %>% group_by(work_setting) %>% ggplot()+geom_boxplot(aes(x = reorder(work_setting, salary_in_usd, FUN = median),salary_in_usd))+labs(x="work_setting")
VIOLIN-PLOT
#Tạo biến factor cho experience_level
summary_table_4 = jobs_in_data2%>%
group_by(experience_level) %>%
summarise(avg_salary = mean(salary_in_usd))
experience_levels_order = c("Entry-level", "Mid-level", "Senior", "Executive")
jobs_in_data2$experience_level = factor(jobs_in_data2$experience_level, levels = experience_levels_order)
ggplot(jobs_in_data2, aes(experience_level, salary_in_usd, fill = experience_level)) +
geom_violin() +
geom_boxplot(width = 0.3, fill = "white", color = "pink", outlier.shape = NA) +
geom_text(data = summary_table_4, aes(x = experience_level, y = avg_salary, label = scales::number_format(scale = 1e-3, accuracy = 1, suffix = "k")(avg_salary)),
color = "black", size = 4, fontface = "bold",vjust=0.2) +
labs(title = "The violin plot Salary", subtitle = "Grouped by Experience Level", x = "Experience Level", y = "Salary (USD)") +
scale_y_continuous(labels = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k"),
breaks = seq(0, 430000, by = 30000)) +
theme_minimal() +
theme(axis.text.x = element_text(size = 12, face = "bold", color = "black"), axis.text.y = element_text(size = 12,face = "bold", color = "black"), title = element_text(size = 13), legend.title = element_text(size = 14), legend.text = element_text(size = 13))
#Tạo biến factor cho company_size
company_size_order = c("S", "M", "L")
jobs_in_data2$company_size = factor(jobs_in_data2$company_size, levels = company_size_order)
summary_table_5 = jobs_in_data2%>%
group_by(company_size) %>%
summarise(avg_salary = mean(salary_in_usd))
ggplot(jobs_in_data2, aes(company_size, salary_in_usd, fill = company_size)) +
geom_violin() +
geom_boxplot(width = 0.3, fill = "white", color = "pink", outlier.shape = NA) +
geom_text(data = summary_table_5, aes(x = company_size, y = avg_salary, label = scales::number_format(scale = 1e-3, accuracy = 1, suffix = "k")(avg_salary)),
color = "black", size = 4, fontface = "bold",vjust=-0.1) +
labs(title = "The violin plot Salary", subtitle = "Grouped by Company Size", x = "Company Size", y = "Salary (USD)") +
scale_y_continuous(labels = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k"),
breaks = seq(0, 430000, by = 30000)) +
theme_minimal() +
theme(axis.text.x = element_text(size = 12, face = "bold", color = "black"), axis.text.y = element_text(size = 12,face = "bold", color = "black"), title = element_text(size = 13), legend.title = element_text(size = 14), legend.text = element_text(size = 13))
HEAT MAP
#Heat map tiền lương trung bình theo job_category nhóm bởi experience_level, company_size và work_setting
summary_table_6 = jobs_in_data2 %>%
group_by(work_setting, company_size, experience_level) %>%
summarize(average_salary = round(mean(salary_in_usd)),.groups = "drop")
summary_table_6 = summary_table_6 %>%
mutate(company_setting = paste(company_size, work_setting, sep = " - ")) %>%
select(-company_size, -work_setting) %>%
select(company_setting, everything()) %>%
arrange(desc(average_salary))
experience_levels_order = c("Entry-level", "Mid-level", "Senior", "Executive")
summary_table_6$experience_level = factor(summary_table_6$experience_level, levels = experience_levels_order)
ggplot(summary_table_6, aes(x = experience_level, y = company_setting, fill = average_salary)) +
geom_tile(color = "white", linewidth = 0.5) +
geom_text(aes(label = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k")(average_salary)), vjust = 0.5, size = 5, fontface = "bold") +
scale_fill_gradient(low = "yellow", high = "blue", name = "Average Salary in USD", labels = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k")) +
labs(title = "Average Salary Heat Map: job_category in 2023", subtitle = "Grouped by experience level, company size and work setting",
x = "Experience Level",
y = "Company size / Work setting") +
theme_minimal() +
theme(axis.text.x = element_text(size = 10, face = "bold", color = "black"), axis.text.y = element_text(size = 10,face = "bold", color = "black"), title = element_text(size = 14), legend.title = element_text(size = 10), legend.text = element_text(size = 10))
Nhìn chung lương trung bình đều tăng theo Experience Level, duy nhất chỉ có đối với Công ty size S với hình thức làm việc Hybrid là giảm dần Mức lương dành cho Executive của công ty size L với hình thức làm việc Remote là cao nhất với 253k => Càng cho thấy triển vọng của Remote trong tương lai
#Heat map tiền lương trung bình theo job_category nhóm bởi experience_level
summary_table_7 = jobs_in_data2 %>%
group_by(job_category, experience_level) %>%
summarise(average_salary = mean(salary_in_usd), .groups = "drop")
experience_levels_order = c("Entry-level", "Mid-level", "Senior", "Executive")
summary_table_7$experience_level = factor(summary_table_7$experience_level, levels = experience_levels_order)
ggplot(summary_table_7, aes(experience_level, job_category, fill = average_salary)) +
geom_tile(color = "white", linewidth = 0.7) +
geom_text(aes(label = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k")(average_salary)), vjust = 0.5, size = 5, fontface = "bold") +
scale_fill_gradient(low = "#CCCCFF", high = "#003399", name = "Avg salary", labels = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k")) +
labs(title = "The Average Salary (USD) in thousand (k)", subtitle = "Grouped by Job Category and Experience Level",
x = "Experience Level",
y = "Job Category") +
theme_minimal() +
theme(axis.text.x = element_text(size = 10, face = "bold", color = "black"), axis.text.y = element_text(size = 10,face = "bold", color = "black"), title = element_text(size = 14), legend.title = element_text(size = 13), legend.text = element_text(size = 13))
Nhìn chung lương trung bình đều tăng theo Experience Level, duy nhất chỉ có đối với ngành Data Analysis thì lương trung bình của Senior cao hơn Executive Mức lương dành cho Executive của ngành Data Science and Research là cao nhất với 212k, hơn nữa thì số lượng job của ngành này cũng cao nhất
#Do ngành Data Analysis có mức lương trung bình dành cho Senior lớn hơn Executive nên sẽ vẽ biểu đổ histogram để xem tính chuẩn của phân phối
#Histogram plot + density của Data Analysis
jobs_in_data2%>%filter(job_category == "Data Analysis")%>%
ggplot(aes(x = salary_in_usd, fill=experience_level)) +
geom_histogram(aes(y = ..density..),color = '#5c082c', fill ='white', bins=30) +
geom_density(alpha=.2)+
labs(title = "Histogram for Salary ($)",x = "Salary in USD",y = "Count") +
theme_classic() +
theme(
plot.title = element_text(color = "#383335", size = 18, face = "bold"),
plot.subtitle = element_text(color = "#F5B0CB",size = 12, face = "bold"),
plot.caption = element_text(face = "italic"))
Hầu như đối với các experience level thì phân phối đều có dạng 2 đỉnh, hay nói cách khác sẽ có 2 điểm là cực đại trong pp, điều này có thể do vấn đề về dữ liệu nên việc lương tb của Senior cao hơn lương tb của Executive cũng có thể giải thích phần nào được
#Top 10 nước có lương trung bình dành cho Data Analysis mức Entry-level cao nhất
summary_table_8 = jobs_in_data2 %>% filter(job_category =="Data Analysis" & experience_level == "Entry-level")%>%
group_by(company_location) %>%
mutate(avg_salary = round(mean(salary_in_usd))) %>%
arrange(desc(avg_salary)) %>%
ungroup()
df_unique1 = distinct(summary_table_8, summary_table_8$company_location, .keep_all = TRUE)%>%head(10)
ggplot(df_unique1, aes(x = reorder(company_location, -avg_salary), y = avg_salary, fill = company_location)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = scales::number_format(accuracy = 1, scale = 1e-3, suffix = "k")(avg_salary)), vjust = -0.5, size = 3, fontface = "bold") +
labs(title = "Top 10 countries with highest average salaries for Entry-level Data Analysis",
x = "Company Location",
y = "Average Salary"
) +
theme_minimal() +
guides(fill = "none") +
theme(axis.text.x = element_text(angle = 45, vjust = 0.5, size = 9, color = "black", face ="bold"), axis.text.y = element_blank(), title = element_text(size = 9), legend.title = element_text(size = 12), legend.text = element_text(size = 12))
Mức lương trung bình dành cho Entry-level của ngành Data Analysis ở Mỹ là cao nhất với 80k USD
jobs_in_data2 %>%
mutate(region=case_when(company_location=="United States" ~ "United States",
company_location=="United Kingdom" ~ "United Kingdom",
company_location %in% c("Croatia",
"Czech Republic", "Denmark", "Estonia", "Finland",
"France", "Germany", "Greece", "Ireland", "Italy",
"Lithuania", "Latvia",
"Netherlands", "Poland", "Portugal", "Romania",
"Slovenia", "Spain", "Sweden") ~ 'Europe',
company_location=="Canada" ~ 'Canada',
company_location == "Australia" ~ "Australia",
company_location %in% c("Armenia",
"India", "Israel", "Japan", "Singapore",
"South Korea", "Qatar", "Saudi Arabia", "Turkey") ~ 'Asia'))%>%
group_by(region, job_category) %>%
summarize(avg_salary=mean(salary_in_usd), .groups = "drop") %>%
ggplot(aes(x=job_category, y=avg_salary, group=region, fill=region)) +
geom_bar(stat='identity', width = 0.8) +
theme(axis.text.x = element_text(angle=90, hjust=1)) +
labs(title = "Average Salary by Job Categry", x="Job Category", y="Average Salary in USD") +
facet_wrap(~region) +
theme(legend.position = "none")