Kto pracuje najbardziej efektywnie w Europie?

Czy wydajność pracy w różnych krajach Europy jest jednakowa? Jak skorzystać z danych Eurostatu w R? Jestem fanem facebookowej strony z różnymi mapkami. Na stronie tej pokazał się ostatnio obrazek z informacją o średniej liczbie godzin jaką w pracy spędzają mieszkańcy poszczególnych krajów (linkował do tego postu). Ale szczerze powiedziawszy co to za informacja? To czy siedzisz w pracy długo czy krótko nie ma (bezpośrednio) związku z tym ile wartości wypracujesz. Sprawdźmy ile warta (w rozumieniu produktu krajowego brutto) jest godzina pracy mieszkańca poszczególnych krajów Europy. Do tego celu skorzystamy z danych Eurostatu, tym bardziej że istnieje bardzo wygodny pakiet R, z którym takie działanie jest banalnie proste. Na początek musimy znaleźć odpowiednie dane. Pakiet eurostat dostarcza nam odpowiednich funkcji:

library(tidyverse)

# install.packages("eurostat")
library(eurostat)

# szukamy odpowiedniej tabeli - dane o średniej liczbie przepracowanych godzin
search_eurostat("Average hours worked per employee") %>% select(code, title, `last update of data`)
codetitlelast update of data
lc_rnum2_r2Average hours worked per employee, by working time, NACE Rev. 2 activity and NUTS 1 regions - LCS surveys 2008 and 201217.12.2015
lc_r04num2Average hours worked per employee, by working time, NACE Rev. 1.1 activity and NUTS 1 regions - LCS survey 200409.03.2011
lc_r00num2Average hours worked per employee, by working time, NACE Rev. 1.1 activity and NUTS 1 regions - LCS survey 200026.03.2009

Widzimy, że mamy 6 tabel z poszukiwanym ciągiem znaków (w opisie). Wykorzystamy jedną z nich zawierającą najwięcej najnowszych danych - lc_rnum2_r2:

# pobieramy dane z tabeli lc_rnum2_r2
working_hours <- get_eurostat("lc_rnum2_r2")

# agregacja (średnie) do poziomu kraju
working_hours_plot <- working_hours %>%
   filter(worktime == "AVG_FTE", # Yearly average in full-time equivalents
          indic_lc == "HRS_WKD_PER_SAL") %>% # Average hours actually worked per year, per employee
   filter(time == max(time)) %>%
   mutate(country = substr(geo, 1, 2)) %>%
   group_by(country) %>%
   summarise(hours = mean(values, na.rm = TRUE)) %>%
   ungroup() %>%
   mutate(hours_per_week = 5*hours/252)

Dane są na poziomie NUTS_1 (czyli makroregionów), ale dane o PKB są na poziomie państw - stąd agregacja (poprzez uśrednienie) stosownych wartości. W tabeli Eurostatu mamy wydzielone kilka kategorii wybieramy odpowiednią (opisane w komentarzu wyżej). To samo robimy, aby uzyskać dane o PKB:

# dane o PKB - szukamy tabeli
search_eurostat("GDP per capita")

# pobieramy tabelę
pkb <- get_eurostat("nama_aux_gph")

# zostawiamy tylko interesujące nas dane
pkb_plot <- pkb %>%
   filter(time == max(working_hours$time)) %>%
   mutate(geo = as.character(geo)) %>%
   filter(nchar(geo) == 2) %>%
   filter(unit == "EUR_HAB", # Euro per inhabitant
          indic_na == "NGDPH") # Nominal Gross Domestic Product per capita
codetitlelast update of data
nama_aux_gphGDP per capita - annual Data27.09.2016
namq_aux_gphGDP per capita - quarterly Data19.09.2014

Pakiet eurostat umożliwia również pobranie danych geograficznych (plików SHP) - nie musimy ich więc szukać w innych serwisach.

library(broom) # dla tidy()

# pobranie pliku SHP
geo <- get_eurostat_geospatial()

map_df <- tidy(geo, region = "NUTS_ID")

county_maps_df <- map_df %>%
   # poziom państw
   filter(nchar(id) == 2) %>%
   # odcinamy wyspy na Atlantyku
   filter(lat > 30)

Mamy dane, mamy mapki - łączymy wszystko razem:

plot_data <- left_join(pkb_plot, working_hours_plot, by = c("geo" = "country")) %>%
   mutate(pkb_h = values/hours) %>%
   left_join(county_maps_df, by = c("geo" = "id"))

Znajdźmy jeszcze środki państw - będzie to przydatne do pozycjonowania tekstu (napisów) na mapie:

county_maps_means_df <- plot_data %>%
   group_by(geo) %>%
   mutate(mlong = mean(long), mlat = mean(lat)) %>%
   ungroup() %>%
   select(geo, mlong, mlat, hours_per_week, values, pkb_h) %>%
   distinct()

Jak wygląda mapa pobrana z Eurostatu?

library(ggrepel) # dla ładnego umieszczenia labelek

ggplot() +
   geom_polygon(data = county_maps_df, aes(long, lat, group = group, fill = id),
                show.legend = FALSE, color = "black") +
   geom_label_repel(data = county_maps_means_df, aes(mlong, mlat, label = geo)) +
   coord_map() +
   labs(x = "", y ="") +
   theme(axis.text = element_blank())

Jest to jak widać Europa, a nawet Unia Europejska. Jak wyglądają częściowe dane? Najpierw PKB na głowę mieszkańca:

plot_data %>%
   select(geo, values) %>%
   distinct() %>%
   arrange(values) %>%
   mutate(geo = factor(geo, levels = geo)) %>%
   ggplot() +
   geom_col(aes(geo, values, fill = ifelse(geo == "PL", "PL", "other")),
            color = "black", show.legend = FALSE) +
   scale_fill_manual(values = c("PL" = "orange", "other" = "lightgreen")) +
   labs(title = "Produkt krajowy brutto na głowę mieszkańca",
        subtitle = "Na podstawie danych Eurostat, stan na koniec 2011 roku",
        x = "", y = "PKB per capita (w €)")

Słupki są ok, ale mapki są ładniejsze:

ggplot() +
   geom_polygon(data = plot_data,
                aes(long, lat, group = group, fill = values),
                color = "black", show.legend = FALSE) +
   geom_label_repel(data = county_maps_means_df,
                    aes(mlong, mlat, label = paste0(geo, ": ", values, " €"))) +
   coord_map() +
   scale_fill_gradient(low = "darkred", high = "yellow", na.value = "gray80") +
   labs(title = "Produkt krajowy brutto na głowę mieszkańca",
        subtitle = "Na podstawie danych Eurostat, stan na koniec 2011 roku",
        x = "", y = "") +
   theme(axis.text = element_blank())

Widać wyraźnie dawny podział na Europę Zachodnią i blok post-sowiecki. Najbogatsze kraje to Norwegia, Szwajcaria (tak wiem - nie jest w UE, ale znalazła się w danych o PKB) i Szwecja. Druga strona skali to Bułgaria, Rumunia, Węgry i Polska. Pamiętajcie, że dane są na koniec 2011 roku (to dość dawno - ale takie dane są w Eurostacie o liczbie przepracowanych godzin, a przecież porównywać należy jabłka z jabłkami). Jak zatem wyglądała średnia liczba przepracowanych w roku godzin na pracownika? Najpierw słupki:

plot_data %>%
   select(geo, hours_per_week) %>%
   distinct() %>%
   filter(!is.na(hours_per_week)) %>%
   arrange(hours_per_week) %>%
   mutate(geo = factor(geo, levels = geo)) %>%
   ggplot() +
   geom_col(aes(geo, hours_per_week, fill = ifelse(geo == "PL", "PL", "other")),
            color = "black", show.legend = FALSE) +
   geom_text(aes(geo, hours_per_week, label = sprintf("%.1f h", hours_per_week)), vjust = 1.2) +
   scale_fill_manual(values = c("PL" = "orange", "other" = "lightgreen")) +
   labs(title = "Średnia liczba godzin przepracowanych w tygodniu przez pracownika",
        subtitle = "Na podstawie danych Eurostat, stan na koniec 2011 roku",
        x = "", y = "")

i jeszcze mapa (od czego się zaczęło - post z facebooka):

ggplot() +
   geom_polygon(data= plot_data,
                aes(long, lat, group = group, fill = hours_per_week),
                color = "black", show.legend = FALSE) +
   geom_label_repel(data = county_maps_means_df %>% filter(!is.na(hours_per_week)),
                    aes(mlong, mlat, label = paste0(geo, ": ", round(hours_per_week, 1), " h"))) +
   coord_map() +
   scale_fill_gradient(low = "darkred", high = "yellow", na.value = "gray80") +
   labs(title = "Średnia liczba godzin przepracowanych w tygodniu",
        subtitle = "Na podstawie danych Eurostat, stan na koniec 2011 roku",
        x = "", y = "") +
   theme(axis.text = element_blank())

Widać różnice w stosunku do wspomnianego postu, a wynikają one z innego źródła danych (ja użyłem Eurostat, Jakub tabel z OECD) jak i okresu (2011 vs 2016). Inne dane również braliśmy pod uwagę (pracownicy na pełny etat i pracownicy na część etatu). Tutaj zabrakło również kilku państw (nie ma Czechów i Słowaków, nie ma krajów nadbałtyckich, a najbardziej mi brak Norwegii). Co widzimy już teraz? Zachodnia Europa pracuje nieco mniej niż część wschodnia, ale jak pamiętamy z poprzedniej mapki - PKB jest ułożone odwrotnie! Policzmy zatem ile euro do PKB wypracowuje średni pracownik w czasie jednej godziny:

ggplot() +
   geom_polygon(data= plot_data, aes(long, lat, group = group, fill = pkb_h),
                color = "black", show.legend = FALSE) +
   geom_label_repel(data = county_maps_means_df %>% filter(!is.na(pkb_h)),
                    aes(mlong, mlat, label = paste0(geo, ": ", round(pkb_h, 1), " €/h"))) +
   coord_map() +
   scale_fill_gradient(low = "darkred", high = "yellow", na.value = "gray80") +
   labs(title = "Kto pracuje najbardziej efektywnie w Europie?",
        subtitle = "PKB na osobę wypracowany przez godzinę\nNa podstawie danych Eurostat, stan na koniec 2011 roku",
        x = "", y = "",
        fill = "PKB na osobę wypracowany przez godzinę") +
   theme(axis.text = element_blank())

Jest to swoista miara wydajności pracy. Oczywiście PKB nie bierze się tylko z samej pracy (pod uwagę brane są inwestycje, konsumpcja). Zestawienie samo w sobie jest ciekawe. A przepis powyżej pozwoli Wam na opracowania swoich, właściwie dowolnych, wskaźników na bazie danych z Eurostat. Oprócz pakietu eurostat istnieje analogiczny dla danych z OECD. Zobaczmy jeszcze jak wygląda czas pracy w poszczególnych częściach Polski. Wszystkie dane mamy już pobrane

left_join(
   map_df %>% filter(substr(id, 1, 2) == "PL", nchar(id) == 3),
   working_hours %>%
      filter(worktime == "AVG_FTE", # Yearly average in full-time equivalents
             indic_lc == "HRS_WKD_PER_SAL") %>% # Average hours actually worked per year, per employee
      filter(time == max(time)) %>%
      filter(substr(geo, 1, 2) == "PL") %>%
      group_by(geo) %>%
      summarise(work = round(5*mean(values, na.rm = TRUE)/252, 2)) %>%
      ungroup() %>%
      mutate(geo = as.character(geo)),
   by = c("id" = "geo")) %>%
   ggplot() +
   geom_polygon(aes(long, lat, group = group, fill = as.factor(work)), color = "black") +
   coord_map() +
   scale_fill_brewer(palette = "YlOrRd", direction = -1) +
   labs(title = "Kto pracuje najdłużej w Polsce?",
        subtitle = "Na podstawie danych Eurostat, stan na koniec 2011 roku",
        x = "", y = "",
        fill = "Średnia liczba godzin pracy w tygodniu") +
   theme(axis.text = element_blank())

O dziwo wcale Mazowsze (z Warszawą na czele) nie pracuje najwięcej. Jak wdać Małopolska ma najwięcej luzu (idealnie pasuje tutaj Kraków - Ocean wolnego czasu Maanamu).