Tento dokument analyzuje údaje z datasetu pracovných ponúk v
AI prostredí.
Hľavný cieľ je na základe dát jasne a zrozumiteľne
odpovedať na praktické otázky:
# Balíčky
packages <- c("tidyverse","lubridate","forcats","skimr","janitor",
"ggplot2","ggthemes","scales","stringr","tidytext",
"ggcorrplot","corrplot","knitr","kableExtra","zoo")
new <- packages[!(packages %in% installed.packages()[,"Package"])]
if(length(new)) install.packages(new, repos = "https://cloud.r-project.org")
invisible(lapply(packages, library, character.only = TRUE))
theme_set(theme_minimal())
options(scipen = 999)
# Tu čistím mená stĺpcov a upravujem typy.
data_path <- "ai_job_dataset.csv"
jobs <- readr::read_csv(data_path, show_col_types = FALSE) %>% clean_names()
Základná charakteristika datasetu
head(jobs, 5)
skimr::skim(jobs)
| Name | jobs |
| Number of rows | 15000 |
| Number of columns | 19 |
| _______________________ | |
| Column type frequency: | |
| Date | 2 |
| character | 12 |
| numeric | 5 |
| ________________________ | |
| Group variables | None |
Variable type: Date
| skim_variable | n_missing | complete_rate | min | max | median | n_unique |
|---|---|---|---|---|---|---|
| posting_date | 0 | 1 | 2024-01-01 | 2025-04-30 | 2024-08-28 | 486 |
| application_deadline | 0 | 1 | 2024-01-16 | 2025-07-11 | 2024-10-12 | 543 |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| job_id | 0 | 1 | 7 | 7 | 0 | 15000 | 0 |
| job_title | 0 | 1 | 10 | 27 | 0 | 20 | 0 |
| salary_currency | 0 | 1 | 3 | 3 | 0 | 3 | 0 |
| experience_level | 0 | 1 | 2 | 2 | 0 | 4 | 0 |
| employment_type | 0 | 1 | 2 | 2 | 0 | 4 | 0 |
| company_location | 0 | 1 | 5 | 14 | 0 | 20 | 0 |
| company_size | 0 | 1 | 1 | 1 | 0 | 3 | 0 |
| employee_residence | 0 | 1 | 5 | 14 | 0 | 20 | 0 |
| required_skills | 0 | 1 | 11 | 71 | 0 | 13663 | 0 |
| education_required | 0 | 1 | 3 | 9 | 0 | 4 | 0 |
| industry | 0 | 1 | 5 | 18 | 0 | 15 | 0 |
| company_name | 0 | 1 | 12 | 26 | 0 | 16 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| salary_usd | 0 | 1 | 115348.97 | 60260.94 | 32519 | 70179.75 | 99705.0 | 146408.5 | 399095 | ▇▅▂▁▁ |
| remote_ratio | 0 | 1 | 49.48 | 40.81 | 0 | 0.00 | 50.0 | 100.0 | 100 | ▇▁▇▁▇ |
| years_experience | 0 | 1 | 6.25 | 5.55 | 0 | 2.00 | 5.0 | 10.0 | 19 | ▇▅▃▂▂ |
| job_description_length | 0 | 1 | 1503.31 | 576.13 | 500 | 1003.75 | 1512.0 | 2000.0 | 2499 | ▇▇▇▇▇ |
| benefits_score | 0 | 1 | 7.50 | 1.45 | 5 | 6.20 | 7.5 | 8.8 | 10 | ▇▇▇▇▇ |
jobs <- jobs %>%
mutate(
posting_date = lubridate::ymd(posting_date),
application_deadline = lubridate::ymd(application_deadline),
company_size = factor(company_size, levels = c("S","M","L"), labels = c("Small","Medium","Large")),
experience_level = factor(experience_level, levels = c("EN","MI","SE","EX"),
labels = c("Entry","Mid","Senior","Executive")),
employment_type = factor(employment_type, levels = c("PT","CT","FL","FT"),
labels = c("Part-time","Contract","Freelance","Full-time")),
remote_ratio = as.integer(remote_ratio)
) %>%
filter(!is.na(salary_usd), salary_usd > 1000) # odstránenie zjavne chybných miezd
Interpretácia: Dátumy a kategórie sú nastavené na „kariérny“ poriadok; odstraňujem len vyslovene nerealisticky nízke mzdy, aby výsledky neboli skreslené.
jobs %>%
ggplot(aes(x = salary_usd)) +
geom_histogram(bins = 40, fill = "steelblue", color = "white") +
scale_x_continuous(labels = scales::label_dollar()) +
labs(title = "Histogram miezd v USD",
x = "Mzda (USD)",
y = "Počet pozícií")
Interpretácia: Vidíme tvar rozdelenia (pravostranný chvost pri vysokých mzdách); dôležité je, kde leží jadro rozdelenia (typický plat).
jobs %>%
ggplot(aes(x = experience_level, y = salary_usd)) +
geom_boxplot(outlier.alpha = 0.3, color = "black", fill = "steelblue") +
scale_y_continuous(labels = scales::label_dollar()) +
labs(title = "Mzdy podľa úrovne skúseností",
x = "Úroveň skúseností",
y = "Mzda (USD)")
Interpretácia: Graf ukazuje, že s rastúcou úrovňou skúseností rastie aj výška mzdy. Medián miezd sa zvyšuje od úrovne Entry až po Executive. Zároveň vidíme, že rozptyl miezd sa pri vyšších pozíciách zväčšuje, čo naznačuje väčšiu variabilitu odmeňovania medzi manažérmi a špecialistami na najvyšších úrovniach.
jobs %>%
mutate(company_size = fct_explicit_na(company_size, na_level = "Unknown")) %>%
group_by(company_location, company_size) %>%
summarise(median_salary = median(salary_usd), n = n(), .groups = "drop") %>%
filter(n >= 20) %>%
arrange(desc(median_salary)) %>%
slice_head(n = 20) %>%
ggplot(aes(
x = reorder(paste(company_location, company_size, sep = " · "), median_salary),
y = median_salary,
fill = company_size
)) +
geom_col(color = "white") +
coord_flip() +
scale_y_continuous(labels = scales::label_dollar()) +
scale_fill_brewer(palette = "Blues") +
labs(
title = "Top 20 kombinácií (lokalita × veľkosť firmy) podľa mediánu mzdy",
x = "Lokalita · Veľkosť firmy",
y = "Medián mzdy (USD)",
fill = "Veľkosť firmy"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "top",
plot.title = element_text(face = "bold", size = 13),
axis.text.y = element_text(size = 10)
)
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `company_size = fct_explicit_na(company_size, na_level =
## "Unknown")`.
## Caused by warning:
## ! `fct_explicit_na()` was deprecated in forcats 1.0.0.
## ℹ Please use `fct_na_value_to_level()` instead.
Interpretácia: Graf ukazuje 20 kombinácií krajín a veľkostí firiem s najvyšším mediánom mzdy. Väčšie spoločnosti (Large) spravidla ponúkajú vyššie platy, najmä v technologicky vyspelých krajinách ako Nemecko, Švajčiarsko či USA. Menšie firmy majú väčšinou nižšie mediány, no občas sa objavia výnimky pri špecializovaných pozíciách.
monthly <- jobs %>%
filter(!is.na(posting_date)) %>%
mutate(month = as.Date(cut(posting_date, "month"))) %>%
group_by(month) %>%
summarise(
n_postings = n(),
median_salary = median(salary_usd),
.groups = "drop"
)
monthly %>%
ggplot(aes(x = month, y = n_postings)) +
geom_line(color = "#4B9CD3", size = 1.2) +
geom_point(color = "#4B9CD3", size = 2) +
labs(
title = "Počet pracovných ponúk v čase",
x = "Mesiac",
y = "Počet ponúk"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Medián mzdy v čase
monthly %>%
ggplot(aes(x = month, y = median_salary)) +
geom_line(color = "#6AA84F", size = 1.2) +
geom_point(color = "#6AA84F", size = 2) +
scale_y_continuous(labels = scales::label_dollar()) +
labs(
title = "Vývoj mediánovej mzdy v čase",
x = "Mesiac",
y = "Medián mzdy (USD)"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))
Interpretácia: Počet pracovných ponúk aj mediánová mzda sa v priebehu mesiacov mierne menia. Zatiaľ čo počet ponúk vykazuje sezónne výkyvy (napr. vyšší v jarných a jesenných mesiacoch), mediánová mzda zostáva relatívne stabilná, s miernym rastom v neskoršom období. To môže odrážať zvýšený dopyt po kvalifikovaných pracovníkoch alebo posun k seniornejším pozíciám.
#Ktoré zručnosti sú najžiadanejšie? (text mining)
skill_counts <- jobs %>%
select(required_skills) %>%
filter(!is.na(required_skills)) %>%
mutate(required_skills = str_replace_all(required_skills, "\\s*,\\s*", ",")) %>%
separate_rows(required_skills, sep = ",") %>%
mutate(skill = str_trim(str_to_title(required_skills))) %>%
filter(skill != "", skill != "Na") %>%
count(skill, sort = TRUE)
skill_counts %>%
slice_max(n, n = 20) %>%
ggplot(aes(x = reorder(skill, n), y = n, fill = n)) +
geom_col(show.legend = FALSE) +
scale_fill_gradient(low = "#A7C7E7", high = "#004C99") +
coord_flip() +
labs(
title = "TOP 20 zručností požadovaných v AI inzerátoch",
x = "Zručnosť",
y = "Počet výskytov"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
axis.text.y = element_text(size = 10)
)
Interpretácia: Najčastejšie požadované zručnosti v AI inzerátoch sú programovacie jazyky a nástroje ako Python, SQL či TensorFlow. Vysoký výskyt technológií spojených so strojovým učením (napr. PyTorch, Machine Learning, Deep Learning) potvrdzuje, že trh práce v AI kladie dôraz na praktické znalosti v dátovej analýze a modelovaní.
num_cols <- jobs %>%
select(salary_usd, remote_ratio, years_experience, job_description_length, benefits_score) %>%
drop_na()
cor_mat <- cor(num_cols, use = "pairwise.complete.obs", method = "pearson")
round(cor_mat, 2)
## salary_usd remote_ratio years_experience
## salary_usd 1.00 0.01 0.74
## remote_ratio 0.01 1.00 0.02
## years_experience 0.74 0.02 1.00
## job_description_length -0.01 0.00 -0.01
## benefits_score 0.00 0.00 -0.01
## job_description_length benefits_score
## salary_usd -0.01 0.00
## remote_ratio 0.00 0.00
## years_experience -0.01 -0.01
## job_description_length 1.00 0.01
## benefits_score 0.01 1.00
ggcorrplot(cor_mat,
lab = TRUE,
hc.order = TRUE,
type = "lower",
colors = c("#6D9EC1", "white", "#E46726"),
lab_size = 3,
title = "Korelačná matica numerických premenných",
ggtheme = theme_minimal())
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the ggcorrplot package.
## Please report the issue at <https://github.com/kassambara/ggcorrplot/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Interpretácia: Najsilnejšia pozitívna korelácia je medzi výškou mzdy (salary_usd) a dĺžkou praxe (years_experience), čo naznačuje, že skúsenosť má zásadný vplyv na odmeňovanie. Ostatné premenné, ako remote_ratio, job_description_length či benefits_score, nevykazujú výrazné vzťahy so mzdou ani medzi sebou, čo poukazuje na to, že tieto faktory nie sú priamo spojené s výškou odmeny.
model_data <- jobs %>%
select(salary_usd, years_experience, remote_ratio, benefits_score, experience_level, company_size, industry) %>%
drop_na()
fit <- lm(salary_usd ~ years_experience + remote_ratio + benefits_score +
experience_level + company_size + industry, data = model_data)
summary(fit)
##
## Call:
## lm(formula = salary_usd ~ years_experience + remote_ratio + benefits_score +
## experience_level + company_size + industry, data = model_data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -93593 -22151 -4197 18654 193413
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 48514.682 2020.149 24.015 <0.0000000000000002
## years_experience -383.935 176.521 -2.175 0.0296
## remote_ratio 3.313 7.210 0.460 0.6459
## benefits_score 212.397 202.890 1.047 0.2952
## experience_levelMid 25378.034 944.256 26.876 <0.0000000000000002
## experience_levelSenior 61060.551 1417.997 43.061 <0.0000000000000002
## experience_levelExecutive 130192.874 2606.331 49.953 <0.0000000000000002
## company_sizeMedium 11942.841 720.735 16.570 <0.0000000000000002
## company_sizeLarge 29266.945 720.825 40.602 <0.0000000000000002
## industryConsulting -432.741 1595.466 -0.271 0.7862
## industryEducation 7.429 1622.080 0.005 0.9963
## industryEnergy -1789.566 1613.592 -1.109 0.2674
## industryFinance -311.745 1610.208 -0.194 0.8465
## industryGaming 277.019 1617.327 0.171 0.8640
## industryGovernment -1220.874 1604.794 -0.761 0.4468
## industryHealthcare -1668.869 1604.647 -1.040 0.2983
## industryManufacturing -472.442 1619.418 -0.292 0.7705
## industryMedia -1387.193 1586.079 -0.875 0.3818
## industryReal Estate 1201.177 1601.103 0.750 0.4531
## industryRetail 1249.123 1579.135 0.791 0.4289
## industryTechnology -308.626 1599.459 -0.193 0.8470
## industryTelecommunications -941.946 1605.025 -0.587 0.5573
## industryTransportation -1964.508 1604.883 -1.224 0.2209
##
## (Intercept) ***
## years_experience *
## remote_ratio
## benefits_score
## experience_levelMid ***
## experience_levelSenior ***
## experience_levelExecutive ***
## company_sizeMedium ***
## company_sizeLarge ***
## industryConsulting
## industryEducation
## industryEnergy
## industryFinance
## industryGaming
## industryGovernment
## industryHealthcare
## industryManufacturing
## industryMedia
## industryReal Estate
## industryRetail
## industryTechnology
## industryTelecommunications
## industryTransportation
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 36020 on 14977 degrees of freedom
## Multiple R-squared: 0.6431, Adjusted R-squared: 0.6426
## F-statistic: 1227 on 22 and 14977 DF, p-value: < 0.00000000000000022
Interpretácia: Model ukazuje, že úroveň skúseností a veľkosť firmy majú najväčší vplyv na výšku mzdy. Oproti Entry-level pozíciám zarábajú Senior pracovníci v priemere o približne 61 000 USD viac, a Executives až o 130 000 USD viac. Práca vo väčších firmách prináša tiež vyššie odmeny (o 12–29 000 USD). Premenné ako práca na diaľku, benefity či odvetvie nepreukázali štatisticky významný vplyv. Model vysvetľuje približne 64 % rozdielov v mzdách, čo potvrdzuje, že kariérne faktory sú kľúčové pri odmeňovaní.
summary_table <- jobs %>%
group_by(experience_level) %>%
summarise(
n = n(),
median_salary = median(salary_usd),
p25 = quantile(salary_usd, 0.25),
p75 = quantile(salary_usd, 0.75),
.groups = "drop"
) %>%
arrange(desc(median_salary))
kable(summary_table, caption = "Mzdy podľa úrovne skúseností",
col.names = c("Úroveň","Počet","Medián","P25","P75")) %>%
kable_styling(bootstrap_options = c("striped","hover","condensed","responsive"),
full_width = FALSE, position = "center")
| Úroveň | Počet | Medián | P25 | P75 |
|---|---|---|---|---|
| Executive | 3760 | 177512.0 | 143966 | 224549.5 |
| Senior | 3741 | 116907.0 | 94173 | 145315.0 |
| Mid | 3781 | 84641.0 | 67621 | 104483.0 |
| Entry | 3718 | 60373.5 | 48516 | 74866.5 |
summary_table %>%
ggplot(aes(x = reorder(experience_level, median_salary), y = median_salary)) +
geom_col(fill = "#4B9CD3") +
coord_flip() +
scale_y_continuous(labels = scales::label_dollar()) +
labs(
title = "Mediánové mzdy podľa úrovne skúseností",
x = "Úroveň skúseností",
y = "Medián mzdy (USD)"
) +
theme_minimal(base_size = 12)
Interpretácia: Mzdy rastú so zvyšujúcou sa úrovňou skúseností. Entry-level pozície majú mediánovú mzdu okolo 60 000 USD, zatiaľ čo Mid-level pracovníci dosahujú približne 85 000 USD. Senior úroveň prináša už vyše 116 000 USD a Executives dosahujú medián 177 000 USD. Rozpätie miezd sa s vyššou úrovňou rozširuje, čo naznačuje väčšie platové rozdiely medzi menej a viac skúsenými manažérmi.