Jednym ze sposobów zrozumienia, jak działa rząd miasta, jest spojrzenie na to, kogo zatrudnia i jak jego pracownicy są wynagradzani. Dane te zawierają nazwiska, nazwę stanowiska i wynagrodzenie pracowników miasta San Francisco w ujęciu rocznym od 2011 do 2014 roku.
Oto kilka pomysłów na eksplorację danych:
Jak zmieniały się wynagrodzenia w czasie między różnymi grupami ludzi?
Jak płaca podstawowa, wynagrodzenie za nadgodziny i świadczenia są rozdzielane pomiędzy różne grupy?
Czy w tym zestawie danych istnieją dowody na dyskryminację płacową ze względu na płeć?
Jak przydzielany jest budżet w zależności od grupy i zakresu obowiązków?
library(ggplot2)
library(dplyr)
##
## Dołączanie pakietu: 'dplyr'
## Następujące obiekty zostały zakryte z 'package:stats':
##
## filter, lag
## Następujące obiekty zostały zakryte z 'package:base':
##
## intersect, setdiff, setequal, union
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.3 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.0
## ✔ readr 2.1.4
## ── 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
# wymiary ramki:
dim(salaries)
## [1] 148654 13
# nazwy kolumn:
names(salaries)
## [1] "Id" "EmployeeName" "JobTitle" "BasePay"
## [5] "OvertimePay" "OtherPay" "Benefits" "TotalPay"
## [9] "TotalPayBenefits" "Year" "Notes" "Agency"
## [13] "Status"
hist(salaries$TotalPay,main="Total Pay", xlab="Pay (in dollars)")
abline(v = mean(salaries$TotalPay),lty="dashed")
abline(v = median(salaries$TotalPay))
legend("topright", legend=c("Mediana","Średnia"),lty=c("solid","dashed"))
par(mfrow=c(2,2))
hist(salaries$TotalPay,main="Total Pay, default breaks", xlab="Pay (in dollars)")
hist(salaries$TotalPay,main="Total Pay, breaks=100", xlab="Pay (in dollars)", breaks=100)
hist(salaries$TotalPay,main="Total Pay, breaks=1000", xlab="Pay (in dollars)",breaks=1000)
hist(salaries$TotalPay,main="Total Pay, Zoomed-in", xlab="Pay (in dollars)", xlim=c(0,1e5), breaks=1000)
salaries2 <- subset(salaries, JobTitle=="Firefighter" & Status=="FT")
dim(salaries2)
## [1] 738 13
par(mfrow=c(2,2))
hist(salaries2$TotalPay,main="Firefighters, default breaks", xlab="Pay (in dollars)")
hist(salaries2$TotalPay,main="Firefighters, breaks=30", xlab="Pay (in dollars)", breaks=30)
hist(salaries2$TotalPay,main="Firefighters, breaks=100", xlab="Pay (in dollars)", breaks=100)
hist(salaries2$TotalPay,main="Firefighters, breaks=1000", xlab="Pay (in dollars)",breaks=1000)
par(mfrow=c(1,1))
boxplot(salaries$TotalPay,main="Total Pay, breaks=1000", ylab="Pay (in dollars)")
Pierwszy raport dotyczy nieparametrycznej estymacji gęstości. Klasycznym nieparametrycznym estymatorem gęstości jest histogram, który dostarcza nieciągłe i stałe oszacowania. W tym raporcie skupiono się na niektórych alternatywach, które zapewniają ciągłe lub nawet gładkie oszacowania zamiast.
Metody kernelowe stanowią ważną klasę gładkich estymatorów
gęstości i zaimplementowane są przez funkcję R density()
.
Estymatory te są w zasadzie tylko lokalnie ważonymi średnimi, a ich
obliczenie jest stosunkowo proste w teorii. W praktyce, różne wybory
sposobu implementacji obliczeń mogą jednak mieć duży wpływ na
rzeczywisty czas obliczeń, a implementację kernelowych estymatorów
gęstości zilustruje trzy punkty:
Metody kernelowe opierają się na jednym lub więcej parametrach regularności, które muszą być dobrane tak, aby osiągnąć właściwą równowagę w dostosowaniu do danych bez zbytniego dostosowywania się do losowej zmienności w danych.
Wybór odpowiedniej ilości regularności jest równie ważny jak wybór metody do użycia w pierwszej kolejności. W rzeczywistości może być ważniejszy. Tak naprawdę nie mamy kompletnej implementacji nieparametrycznego estymatora dopóki nie zaimplementujemy automatycznego, opartego na danych sposobu wyboru ilości regulacji.
Implementacja tylko obliczeń dla oceny estymatora jądra, powiedzmy, i pozostawiając to całkowicie użytkownikowi wyboru szerokości pasma jest pracą w połowie wykonaną. Metody i implementacje do wyboru szerokości pasma są więc w tym raporcie omówione dość szczegółowo.
W ostatniej części przeprowadzona jest analiza prawdopodobieństwa. Robi się to w celu dalszego wyjaśnienia, dlaczego potrzebne są estymatory z regularyzacją w celu uniknięcia nadmiernego dopasowania do danych, oraz dlaczego nie istnieje w ogóle nieparametryczny maksymalnego prawdopodobieństwa estymatora gęstości. Regularyzację prawdopodobieństwamożna osiągnąć poprzez ograniczenie szacunków gęstości do rodziny coraz bardziej elastycznych gęstości parametrycznych, które są dopasowane do danych. Jest to znane jako metoda sit. Inne podejście opiera się na rozszerzeniach bazowych, ale w obu przypadkach automatyczny wybór wielkości regularności jest tak samo ważny jak w przypadku metod jądrowych.
Aby utworzyć wykres gęstości jądra, musisz oszacować gęstość jądra. W tym celu można użyć funkcji density, a następnie przekazać obiekt density do funkcji plot.
# dane
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data)
# Kernel density plot
plot(d, lwd = 2, main = "Default kernel density plot")
Argument jądra funkcji gęstości domyślnie używa jądra gaussowskiego (kernel = “gaussian”), ale dostępnych jest więcej typów jądra, takich jak “prostokątne”, “trójkątne”, “epanechnikov”, “biweight”, “cosine” i “optcosine”. Wybór będzie zależał od twoich danych, ale w większości scenariuszy wartość domyślna jest najbardziej zalecana.
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
kernel = "rectangular")
# Kernel density plot
plot(d, lwd = 2, main = "Rectangular kernel")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
kernel = "triangular")
# Kernel density plot
plot(d, lwd = 2, main = "Triangular kernel")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
kernel = "epanechnikov")
# Kernel density plot
plot(d, lwd = 2, main = "Epanechnikov kernel")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
kernel = "biweight")
# Kernel density plot
plot(d, lwd = 2, main = "Biweight kernel")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
kernel = "cosine")
# Kernel density plot
plot(d, lwd = 2, main = "Cosine kernel")
Argument bw funkcji gęstości pozwala na zmianę używanego pasma wygładzania. Możesz przekazać wartość lub ciąg znaków podający regułę wyboru lub funkcję. Domyślną wartością jest “nrd0” (lub bw.nrd0(.)), która implementuje podejście oparte na zasadzie reguły kciuka :-) Inne dostępne opcje to:
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
bw = "nrd")
# Kernel density plot
plot(d, lwd = 2, main = "nrd bandwidth")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
bw = "ucv")
# Kernel density plot
plot(d, lwd = 2, main = "ucv bandwidth")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
bw = "bcv")
# Kernel density plot
plot(d, lwd = 2, main = "bcv bandwidth")
# Data
set.seed(14012021)
data <- rnorm(200, mean = 4)
# Kernel density estimation
d <- density(data,
bw = "SJ")
# Kernel density plot
plot(d, lwd = 2, main = "SJ bandwidth")
Szerokość pasma musi być bardzo starannie dobrana! Mała szerokość pasma spowoduje powstanie nadmiernie dopasowanej krzywej, natomiast zbyt duża szerokość pasma spowoduje powstanie krzywej nadmiernie wygładzonej.
Wykorzystując dowolną funkcję R do estymacji funkcji gęstości oszacuj jej przebieg dla wynagrodzeń (zbiór danych salaries) strażaków w San Francisco. Wykorzystaj metody graficzne dostępne w pakiecie ggplot2. Mile widziane przekroje oraz odpowiedzi na pytania badawcze zadane na wstępie.
firefighters <- salaries %>% filter(grepl("fire", JobTitle, ignore.case = TRUE))
d <- density(firefighters$TotalPay, na.rm = TRUE)
plot(d, lwd = 2, main = "Default kernel density plot")
Na wykresie widać jedno wyraźne wybrzuszenie, ten najwyższy punkt przypada na wartość 140 000 USD, oznacza to, że większość strażaków zarabia w pobliżu tej kwoty.Na początku wykresu widać również drugie, mniejsze wybrzuszenie, które może odpowiadać drugiej grupie wyngrodzeń wśród starżaków. Mogą być to pracownicy, którzy wykonują mniej nadgodzin niż pozostali pracownicy.
Jak przydzielany jest budżet w zależności od grupy i zakresu obowiązków?
#10 najlepiej opłacalnych stanowisk w grupie
library(ggplot2)
library(dplyr)
budget_by_job_title <- salaries %>%
group_by(JobTitle) %>%
summarise(total_budget = sum(TotalPay, na.rm = TRUE))
firefighter_jobs <- budget_by_job_title %>% filter(grepl("fire", JobTitle, ignore.case = TRUE))
top_budget_firefighter_jobs <- firefighter_jobs[order(-firefighter_jobs$total_budget), ][1:10, ]
ggplot(top_budget_firefighter_jobs, aes(x = reorder(JobTitle, total_budget), y = total_budget)) +
geom_bar(stat = "identity", fill = "pink") +
ggtitle("10 najlepiej opłacanych stanowisk strażaków") +
xlab("Stanowisko") +
ylab("Całkowite wynagrodzenie") +
coord_flip()
#10 najgorzej opłacalnych stanowisk w grupie
firefighter_jobs <- budget_by_job_title %>% filter(grepl("fire", JobTitle, ignore.case = TRUE))
bottom_budget_firefighter_jobs <- firefighter_jobs[order(firefighter_jobs$total_budget), ][1:10, ]
ggplot(bottom_budget_firefighter_jobs, aes(x = reorder(JobTitle, total_budget), y = total_budget)) +
geom_bar(stat = "identity", fill = "purple") +
ggtitle("10 najgorzej opłacanych stanowisk strażaków") +
xlab("Stanowisko") +
ylab("Całkowite wynagrodzenie") +
coord_flip()
Na podstawie wykresów możemy zaobserwować, że wynagrodzenia strażaków w San Francisco znacząco różnią się w zależności od poziomu stanowiska i zakresu obowiązków. Najlepiej opłacane są stanowiska na poziomach zarządczych i menadżerskich. Najniżej opłacanymi stanowiskami są stanowiska asystenckie/zastępcze i zapewniające wsparcie operacyjne, najprawdopodobniej outsourcingowe.Za pomocą wykresów można wnioskować, że budżet w straży pożarnej, jest przydzielany na podstawie zakresów obowiązków pracowników i zajmowanych przez nich stanowisk.
Jak zmieniały się wynagrodzenia w czasie między różnymi grupami ludzi?
firefighters <- salaries %>% filter(grepl("fire", JobTitle, ignore.case = TRUE))
ggplot(firefighters, aes(x = TotalPay, fill = as.factor(Year))) +
geom_density(alpha = 0.4) +
labs(title = "Gęstość wynagrodzeń w służbach pożarniczych",
x = "Wynagrodzenie",
y = "Gęstość") +
theme_minimal()
W latach 2011-2014 wynagrodzenia w służbach pożarniczych wydają się być stosunkowo stabilne, z niewielkimi zmianami w gęstości wynagrodzeń. To może sugerować, że nie było dużych wahań w polityce płacowej w tym okresie. Chociaż wynagrodzenia były stosunkowo stabilne, można zauważyć pewne różnice w gęstości wynagrodzeń między poszczególnymi latami. Na przykład, w 2013 roku wynagrodzenia były bardziej rozproszone, co może wskazywać na większą różnorodność w wynagrodzeniach w tym roku.
Czy w tym zestawie danych istnieją dowody na dyskryminację płacową ze względu na płeć?
Tego nie jesteśmy w stanie okreslić z powodu braku podziału na płeć, w angielskim nie występuje forma osobowa dla nazw określających zawody, nie da się też tego stwierdzić po imieniu i nazwisku, gdyż nie ma tam zależności, które mogłyby określić płeć (np. w polskim imiona żeńskie kończą się literą -a)
Jak płaca podstawowa, wynagrodzenie za nadgodziny i świadczenia są rozdzielane pomiędzy różne grupy?
Na poniższym wykresie widzimy 4 grupy. Grupa niebieska, posiadająca najniższe wynagrodzenia podstawowe. Jest to najbardziej liczebna grupa. Grupa czerwona, mająca średnio wyższe wynagrodzenie niż w grupie 1, z większą różnorodnością wynagrodzeń. Grupa żółta, ma jeszcze wyższe płace podstawowe i rozkład bardziej rozproszony, co sugeruje większe zróżnicowanie stanowisk.Grupa ciemnoniebieska, która posiada najwyższe wynagrodzenia podstawowe.
Na poniższym wykresie można zauważyć, że dla każdej grupy gęstość jest bardzo bliska blisko zeru, co oznacza, że większość pracowników niezależnie od grupy płacowej otrzymuje bardzo niewielkie lub zerowe wynagrodzenie za nadgodziny.
Grupa niebieska ma głównie bardzo niskie lub zerowe świadczenia. Grupa czerwona otrzymuje nieco wyższe świadczenia, ze szczytem w okolicach 20,000, co wskazuje na umiarkowane kwoty. Grupa żółta ma wyższe świadczenia ze szczytem wokół 30,000 i większym zróżnicowaniem. Grupa ciemnoniebieska ma najwyższe świadczenia, ale tylko niewielka część osób otrzymuje bardzo wysokie kwoty
Wnioski
Podział świadczeń różni się między grupami płacowymi. W wyższych grupach płacowych (PayGroup 3 i 4) świadczenia są znacząco wyższe i bardziej zróżnicowane, co może odzwierciedlać dodatkowe korzyści i świadczenia oferowane osobom na stanowiskach menadżerskich. Niższe grupy (PayGroup 1 i 2) otrzymują znacznie mniejsze świadczenia, co sugeruje, że są to osoby na stanowiskach młodszych specjalistów, o niższych kwalifikacjach.