Page not found
-The page you requested cannot be found (perhaps it was moved or renamed).
-You may want to try searching to find the page's new location, or use -the table of contents to find the page you are looking for.
-diff --git a/docs/_book/404.html b/docs/_book/404.html deleted file mode 100644 index 072e41a..0000000 --- a/docs/_book/404.html +++ /dev/null @@ -1,402 +0,0 @@ - - -
- - - -The page you requested cannot be found (perhaps it was moved or renamed).
-You may want to try searching to find the page's new location, or use -the table of contents to find the page you are looking for.
-Transformacja danych jest niezwykle ważnym elementem dobrze zrobionego raportu. Dane te powinny być prezentowane w sposób czytelny i ułatwiający ich porównywanie. To od potrzeby biznesowej zależy w jaki sposób powinniśmy przedstwiać dane. Np. dysponując wynikami finansowymi zbieranymi co miesiąc przez trzy lata bo planowania budżetu na następny rok przyda nam się prezentacja ich w formacie wąskim, czyli skupionym na wydatkach względem każdego roku. Jednakże, jeżeli chcielibyśmy kontrolować wydatki w tym następnym roku prezentacja danych w formacie szerokim będzie bardziej korzystna, gdyż będziemy mieli informację ile średnio wydajemy w danym miesiącu i na bieżąco będziemy mogli podejmować decyzję o inwestowaniu lub zaciskaniu pasa.
-Niekiedy jednak dane mają bardziej skomplikowaną formę i np. składają się z wielu tabel. Wówczas dla łatwiejszego uzyskania informacji biznesowej będzie połączenie tych tabel. Takie operacje w połączeniu z odpowiednią agregacją i grupowaniem zdecydowanie ułatwia wgląd w aktualną sytuację.
-Ostatnim tematem, na temat któtego ta notatka traktuje są operacje na napisach i datach. Bardzo łatwo uzmysłowić sobie przydatność w posługiwaniu się takimi operacjami. Ułatwia to konstruowanie prostych funkcji, które są kluczowe w każdym projekcie. Chociażby bazując na imionach i nazwiskach pewnych obywateli Polski łatwo wskazać z dużą pewnością kobiety w tym zbiorze sprawdzając ostatnią literę ich imienia (tj. czy dane imie kończy się na literę “a”).
-Dane najczęściej są przedstawiane w postaci tabelarycznej. Jednak mogą być w tej tabeli różnie sformatowane. Wyróżnia się między innymi szeroką reprezentacje danych i wąską reprezentacje danych. W zależności od tego, co chcemy z nimi zrobić czasami trzeba przejść z jednej postaci do drugiej. Aby przetransformować dane korzysta się z funkcji z pakietów dplyr i tidyverse.
-O postaci szerokiej mówimy, gdy pojedyncza zmienna jest rozdzielona pomiędzy kilka kolumn. Różnicę najłatwiej jest pokazać na przykładzie. W tym celu wykorzystamy wbudowany zbiór danych sleep
zawierający informacje o wpływie dwóch leków nasennych na ilość przespanych godzin. Kolumna extra
zawiera informacje o ilości dodatkowo przespanych godzin.
-extra - | --group - | --ID - | -
---|---|---|
-0.7 - | --1 - | --1 - | -
--1.6 - | --1 - | --2 - | -
--0.2 - | --1 - | --3 - | -
--1.2 - | --1 - | --4 - | -
--0.1 - | --1 - | --5 - | -
-3.4 - | --1 - | --6 - | -
Dane są przedstawione w postaci wąskiej, każda zmienna jest przedstawiona w oddzielnej kolumnie. Teraz ‘rozbijmy’ kolumnę group
na group 1
i group 2
.
-ID - | --group 1 - | --group 2 - | -
---|---|---|
-1 - | --0.7 - | --1.9 - | -
-2 - | ---1.6 - | --0.8 - | -
-3 - | ---0.2 - | --1.1 - | -
-4 - | ---1.2 - | --0.1 - | -
-5 - | ---0.1 - | ---0.1 - | -
-6 - | --3.4 - | --4.4 - | -
-7 - | --3.7 - | --5.5 - | -
-8 - | --0.8 - | --1.6 - | -
-9 - | --0.0 - | --4.6 - | -
-10 - | --2.0 - | --3.4 - | -
Można zaobserwować, że wartości z kolumny extra
zostały wpisane w poszczególne komórki, a kolumna group
została podzielona na dwie oddzielne kolumny group 1
i group 2
. Tak sformatowane dane nazywamy szeroką reprezentacją danych.
Aby przejść z wąskiego formatu przedstawiania danych do szerokiego, można użyć funkcji spread()
z pakietu dplyr.
Funkcja spread(dataset,key,value)
przyjmuje trzy agrumenty:
dataset
- zbiór danych w formacie wąskim,
key
- kolumna (klucz) odpowiadająca kolumnie, która ma zostać rozłożona,
value
- kolumna, w której znajdują się wartości wypełniające nowe kolumny.
<- spread(sleep, group, extra)
- szeroka colnames(szeroka) = c("ID","group 1","group 2")
-kable_styling(kable(head(szeroka)), position = "center")
-ID - | --group 1 - | --group 2 - | -
---|---|---|
-1 - | --0.7 - | --1.9 - | -
-2 - | ---1.6 - | --0.8 - | -
-3 - | ---0.2 - | --1.1 - | -
-4 - | ---1.2 - | --0.1 - | -
-5 - | ---0.1 - | ---0.1 - | -
-6 - | --3.4 - | --4.4 - | -
Drugą opcją na uzyskanie tego samego rezultatu jest użycie funkcji pivot_wider
z pakietu tidyverse.
Funkcja przyjmuje dwa argumenty pivot_wider(names_from = name, values_from = value)
:
name
- nazwa kolumny, która ma zostać rozłożona,
value
- nazwa kolumny, w której znajdują się wartości.
%>%
- sleep pivot_wider(names_from = group, values_from = extra)
Można wrócić z postaci szerokiej do wąskiej. W tym celu należy użyć funkcji gather()
z pakietu tidyr.
Funkcja gather(dataset, key, value, other)
przyjmuje również trzy argumenty:
dataset
- zbiór danych w formacie szerokim,
key
- nazwy kolumn z kluczami,
value
- nazwy kolumn z wartościami,
other
- kolumny dataset
, które mają być zawarte w nowej tabeli.
Aby wrócić do postaci wąskiej nałóżmy funkcję gather
na wygenerowaną wcześniej tabele szeroka
.
kable_styling(kable(head(szeroka %>%
-gather(group, extra, -ID))),position = "center")
-ID - | --group - | --extra - | -
---|---|---|
-1 - | --1 - | --0.7 - | -
-2 - | --1 - | ---1.6 - | -
-3 - | --1 - | ---0.2 - | -
-4 - | --1 - | ---1.2 - | -
-5 - | --1 - | ---0.1 - | -
-6 - | --1 - | --3.4 - | -
Drugą funkcją, która umożliwia przejście z szerokiej reprezentacji danych do wąskiej jest funkcja pivot_longer
z pakietu tidyverse.
Funkcja pivot_longer(col_names, names_to = name, values_to = value)
przyjmuje trzy argumenty
col_names
- ciąg nazw kolumn, które chcemy złączyć,
name
- nazwa nowo powstałej kolumny,
value
- nazwa kolumny, w której pojawią się wartości.
kable_styling(kable(head(szeroka %>%
-pivot_longer(c("1", "2"), names_to = "group", values_to = "extra"))),
- position = "center")
Mamy dwie tabele danych tab1 z małymi literami oraz tab2 z wielkimi literami:
--indeks - | --litery - | -
---|---|
-1 - | --a - | -
-2 - | --b - | -
-3 - | --c - | -
-4 - | --d - | -
-5 - | --e - | -
-6 - | --f - | -
-indeks - | --LITERY - | -
---|---|
-4 - | --E - | -
-5 - | --F - | -
-6 - | --G - | -
-7 - | --H - | -
-8 - | --I - | -
-9 - | --J - | -
gdzie x
= tab1, a y
= tab2.
Aby połączyć dwie tabele danych na podstawie wskazanych kolumn lub kolumn o wspólnej nazwie można użyć przykładowych funkcji.
-Dostępna w bazowym R. Domyślnie funkcja ta łączy tabele względem nazw kolumn, które są wspólne.
-<- merge(x = tab1, y = tab2)
- tabela kable(tabela)
-indeks - | --litery - | --LITERY - | -
---|---|---|
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
Jeśli chcemy być pewni, że tabele zostaną połączone po odpowiedniej kolumnie, możemy przekazać nazwę tej kolumny w argumencie. W tym przypadku:
-merge(tab1, tab2, by = "indeks") # INNER JOIN
Jeśli jest więcej kolumn, po których chcemy połączyć tabele, wystarczy przekazać w argumencie by
wektor z nazwami tych kolumn.
Gdy nazwy kolumn po których chcemy złączyć tabele różnią się, należy wykorzystać argument by.*
. Załóżmy, że kolumna tabeli tab1 - indeks zmieniła nazwę na index, zatem:
merge(tab1, tab2, by.x = "index", by.y = "indeks")
Wartości kolumn indeks
w tab1 oraz tab2 różnią się. Dlatego korzystając z funkcji bez dodatkowych argumentów tracimy dane.
Aby zapobiec traceniu danych z poszczególnych tabel należy skorzystać z argumentu all
, brakujące wartości zostaną uzupełnione NA
:
merge(tab1, tab2, all.x = TRUE) # LEFT JOIN
-merge(tab1, tab2, all.y = TRUE) # RIGHT JOIN
-merge(tab1, tab2, all = TRUE) # OUTER JOIN
Dostajemy wtedy kolejno:
--indeks - | --litery - | --LITERY - | -
---|---|---|
-1 - | --a - | --NA - | -
-2 - | --b - | --NA - | -
-3 - | --c - | --NA - | -
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
-indeks - | --litery - | --LITERY - | -
---|---|---|
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
-7 - | --NA - | --H - | -
-8 - | --NA - | --I - | -
-9 - | --NA - | --J - | -
-indeks - | --litery - | --LITERY - | -
---|---|---|
-1 - | --a - | --NA - | -
-2 - | --b - | --NA - | -
-3 - | --c - | --NA - | -
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
-7 - | --NA - | --H - | -
-8 - | --NA - | --I - | -
-9 - | --NA - | --J - | -
Bez sprecyzowania argumentu sort
wiersze wyniku merge() zostaną posortowane leksykograficznie po wspólnych kolumnach. Gdy sort = FALSE
wiersze będą w nieokreślonej kolejności.
Kolumny złączonej tabeli to najpierw kolumny wspólne, następnie pozostałe z x
a na końcu pozostałe z y
, co widać na przykładach.
Funkcja z paczki dplyr
. Tabele x
i y
powinny zwykle pochodzić z tego samego źródła danych, ale jeśli copy = TRUE
, y
zostanie automatycznie skopiowany do tego samego źródła co x
.
Są cztery typy join zmieniających:
-left_join()
- zwraca wszystkie wiersze z x
i wszystkie kolumny z x
i y
. Wiersze w x
bez dopasowania w y
będą miały wartości NA
w nowych kolumnach. Jeśli istnieje wiele dopasowań między x
a y
, zwracane są wszystkie kombinacje dopasowań<- left_join(tab1, tab2)
- tabela kable(tabela)
-indeks - | --litery - | --LITERY - | -
---|---|---|
-1 - | --a - | --NA - | -
-2 - | --b - | --NA - | -
-3 - | --c - | --NA - | -
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
-6 - | --z - | --G - | -
right_join()
- analogicznie do left_join()
, ale zwraca wszystkie wiersze z y
, a wiersze bez dopasowania w x
będą miały wartości NA
inner_join()
- zwraca wszystkie wiersze z x
, w których znajdują się pasujące wartości w y
, oraz wszystkie kolumny z x
i y
. Jeśli istnieje wiele dopasowań między x
a y
, zwracane są wszystkie kombinacje dopasowań.
<- inner_join(tab1, tab2)
- tabela kable(tabela)
-indeks - | --litery - | --LITERY - | -
---|---|---|
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
-6 - | --z - | --G - | -
full_join()
- zwraca wszystkie wiersze i wszystkie kolumny zarówno z x
, jak i y
. Jeśli nie ma pasujących wartości, zwraca NA
dla brakujących.<- full_join(tab1, tab2)
- tabela kable(tabela)
-indeks - | --litery - | --LITERY - | -
---|---|---|
-1 - | --a - | --NA - | -
-2 - | --b - | --NA - | -
-3 - | --c - | --NA - | -
-4 - | --d - | --E - | -
-5 - | --e - | --F - | -
-6 - | --f - | --G - | -
-6 - | --z - | --G - | -
-7 - | --NA - | --H - | -
-8 - | --NA - | --I - | -
-9 - | --NA - | --J - | -
Argument by
przyjmuje wektor nazw zmiennych do połączenia. Jeśli by = NULL
funkcja *_join()
domyślnie połączy tabele dopasowując wartości ze wszystkich kolumn o wspólnych nazwach w obu tabelach.
Większość poniższych funkcji pochodzi z pakietu stringi.
-Wyznaczanie długości napisów. -Funkcja stri_lenght() zwraca długości poszczególnych napisów w danym wektorze, a stri_isempty() sprawdza, które napisy są puste -> ’’.
Łączenie i powielanie napisów. -Funkcja używana do łączenia kilku wektorów napisów w inny wektor napisów lub nawet w jeden napis, jest stri_paste() i jej warianty.
Przykład:
-<- LETTERS[1:3]
- x <- letters[1:3]
- y <- '!'
- z stri_paste(x, y, z)
## [1] "Aa!" "Bb!" "Cc!"
-Funkcja stri_wrap() wstawia znaki nowego wiersza (n), by napis po wyświetleniu np. przy funkcji cat() miał szerokość nie większą, niż podana, jeżeli to możliwe.
-W przypadku przetwarzania tekstów pochodzących np. z formularzy na stronach internetowych może zachodzić potrzeba usunięcia tzw. białych znaków, np. spacji z początku lub końca napisu. Możemy to zrobić przy użyciu funkcji stri_trim(). Operacja w pewnym sensie odwrotną do tej można wykonać przy użyciu funkcji stri_pad().
-Przykład:
-stri_trim(' Mama i tata\n')
## [1] "Mama i tata"
-Przykład:
-as.character(list(1L, mean, NULL, pi, FALSE))
## [1] "1" "function (x, ...) \nUseMethod(\"mean\")" "NULL" "3.14159265358979"
-## [5] "FALSE"
-<-data.frame(a=c(TRUE, FALSE, FALSE), b=as.integer(c(1, 2, 3)))
- x as.character(x)
## [1] "c(TRUE, FALSE, FALSE)" "1:3"
-Przykład:
-stri_trans_toupper('chcemy duże litery')
## [1] "CHCEMY DUŻE LITERY"
-stri_trans_tolower('ChCemY MałE LiTErY')
## [1] "chcemy małe litery"
-stri_trans_char('zastępowanie znaków', 'ąćęłńóśżź', 'acelnoszz')
## [1] "zastepowanie znakow"
-stri_trans_general('żółć', 'Latin-ASCII')
## [1] "zolc"
-Przykład:
-<- 'Lasy, pola, pastwiska, koszą traktorem'
- x stri_sub(x, 7)
## [1] "pola, pastwiska, koszą traktorem"
-Przykład:
-<- Sys.Date()) (data
## [1] "2023-10-12"
-<- Sys.time()) (czas
## [1] "2023-10-12 16:13:32 CEST"
-Przykład:
- data
## [1] "2023-10-12"
--365 data
## [1] "2022-10-12"
-+365 data
## [1] "2024-10-11"
-<- data-as.Date('2021-01-01')) (d
## Time difference of 1014 days
-Przykład:
-strftime(czas, '%Y-%m-%d %H:%M:%S %Z')
## [1] "2023-10-12 16:13:32 CEST"
-Do znajdowania “najstarszej” i “najmłodszej” daty używamy funkcji max() oraz min().
Do pracy ze strefami czasowymi możemy używać poniższych funkcji:
Na początku zajmiemy się szeroko pojętą czystością kodu. Aby dany kod mógł aspirować do takiego miana, musi przede wszystkim spełniać dwa podstawowe warunki:
-Aby kod był łatwy do zrozumienia musi być przede wszystkim czytelny. Niewątpliwie pomoże w\(~\)tym odpowiednie nazwanie zmiennych, zadbanie o to, żeby wszystkie użyte funkcje i obiekty miały swoją określoną rolę oraz by relacje między nimi były zrozumiałe.
-Tworząc kod powinniśmy myśleć o tym, że będzie on w przyszłości wykorzystywany. Aby to ułatwić, musi być napisany w taki sposób, żeby można było nanieść drobne poprawki lub zmienić dane bez konieczności zmieniania całego kodu.
-Jeśli te dwa warunki nie są spełnione, istnieje obawa, że wprowadzenie nawet najmniejszych zmian całkowicie zniszczy kod.
-Nieuporządkowany i nieklarowny kod może sprawić w przyszłości wiele kłopotów, takich jak na przykład:
-Jeśli my lub ktokolwiek inny będzie chciał w przyszłości wykorzystać taki kod z pewnością straci mnóstwo czasu na próby jego przeczytania i zrozumienia. Gdy już mu się to uda, może napotkać kolejny problem w postaci trudności z wprowadzeniem jakichkolwiek zmian.
-Złe napisanie kodu może spowodować, że po jego jedynym użyciu stanie się bezwartościowy. Nie będzie sensu wprowadzać w nim jakichkolwiek zmian (gdyż będzie to zbyt pracochłonne), ani w żaden sposób rozwinąć by mógł posłużyć do przyszłych projektów (gdyż nawet najmniejsze zmiany mogą ,,zepsuć’’ istniejący kod).
-W nieczytelnym i napisanym w sposób niezrozumiały kodzie, łatwo przemycić błędy, które na pierwszy rzut oka są niewidoczne, ale wychodzą na jaw później.
-Aby tworzyć czysty kod musimy pamiętać o kilku zasadach. Jedną z nich jest odpowiednie nazywanie zmiennych. Nie powinniśmy używać do tego skrótów, czy przypadkowych znaków. Idealna nazwa od razu wskazuje na to, czym jest dany obiekt oraz co oznacza. Przedstawia zamiary, jakie mamy do nazywanego obiektu.
-Równie ważne jest, aby w nazwach nie znajdywały się błędy lub informacje, które mogą wprowadzić potencjalnego czytelnika w błąd. Mówimy tu np. o:
-- nazwaniu kilku obiektów zbyt podobnie,
-- użyciu do nazwania listy (np. osób) słowa \(\mathtt{List}\), choć w rzeczywistości ta ,,lista’’ osób może być wektorem,
-- użyciu trudno rozróżnialnych znaków (takich jak np. 0
i O
),
-- nazwaniu wszystkich obiektów za pomocą jednej litery i cyfry (np. \(x_1,x_2,...,x_n\)).
Jakie powinny być idealne nazwy obiektów w R? Oto kilka wskazówek:
-- zrozumiałe dla osób, dla których jest przeznaczony kod,
-- utrzymane w jednym stylu,
-- łatwe do zrozumienia i napisania,
-- nazwa obiektu powinna być rzeczownikiem, który wskazuje na to, z czym mamy do czynienia,
-- nazwa funkcji powinna być czasownikiem wskazującym na to, co robi dana funkcja.
W tym rozdziale dowiemy się jak pisać ,,dobre’’ funkcje. Tutaj również musimy pamiętać o kilku zasadach.
-Funkcje powinny:
-- być możliwie jak najkrótsze,
-- odpowiadać za jedno pojedyncze zadanie,
-- być na jednym poziomie abstrakcji,
-- mieć maksymalnie 3
parametry.
To znaczy, że nie jest wskazane, aby tworzyć jedną wielką funkcję, która np. wylicza kilkanaście rzeczy, aby na końcu wygenerować jeden wynik. Zamiast tego lepiej stworzyć kilka mniejszych funkcji, które będą się odwoływały do poprzednich. Dzięki temu nasz kod będzie bardziej przejrzysty oraz w prosty sposób będzie można sprawdzić, czy pojedyncze funkcje działają poprawnie.
-Co więcej, nie ma sensu tworzyć funkcji, która zwraca nam już oprawioną tabelę z wynikami. Lepiej, gdy zwraca surowe wyniki, a tworzeniem tabeli zajmuje się kolejna funkcja.
-Przykładowa, poprawnie napisana funkcja:
-= function(sample, alpha) {
- calculate_conf_interval = length(sample)
- len = length(sample[sample == 1])
- successes = successes / n
- mi = sqrt(mi * (1 - mi) / len)
- se = qt(1 - alpha / 2, len - 1)
- quantile = mi - quantile * se
- left = mi + quantile * se
- right return(c(left, right))
- }
Przykładowa funkcja, napisana w ,,nieładny’’ sposób:
-= function(x,y,temp1,temp2){
- func=length(x)
- n <-length(x[x==1])
- s = s/n
- m = sqrt(mi *(1- m)/n)
- sgm <-qt(1 - y /2,len-1)
- q= (s + 0.5 * q ^ 2) /(n + q ^ 2)
- tmp = sqrt(tmp *(1 - tmp)/ (n+ q^2))
- se <- tmp- q* se
- l= tmp + q*se
- r return(c(l,r))}
Główne problemy:
-- czasem przypisanie jest za pomocą =
, czasem <-
,
-- brak spacji po przecinkach,
-- brak spacji pomiędzy +
, -
, *
, /
, itd,
-- niepoprawnie umiejscowione nawiasy {
, }
.
-- nazwa funkcji nie opisuje, co robi ta funkcja,
-- zmienne mają nic nieznaczące i jednoliterowe nazwy,
-- nazwa zmiennej tmp
także nie mówi, czym ona jest,
-- dwa nieużywane parametry funkcji.
Zazwyczaj komentarze do kodu nie są potrzebne, a wręcz zbędne. Dzieje się tak, ponieważ dobrze napisany kod powinien sam się tłumaczyć, tzn. być na tyle zrozumiałym, żeby dodatkowe komentarze nie były potrzebne.
-Jeśli jednak w kodzie jest bałagan, dodatkowe komentarze mogą wręcz wprowadzić dodatkowy chaos.
-Od tej reguły są jednak pewne wyjątki. Jeśli używamy niezbyt oczywistych implementacji lub ,,sztuczek programistycznych’’ warto wspomnieć w komentarzu, co się w danej chwili dzieje. Wyjątkiem są też komentarze informujące o tym, co trzeba jeszcze zrobić lub o potrzebie poprawienia jakiejś części kodu.
-W kontekście pisania czystego i wydajnego kodu, należy wziąć pod uwagę rozróżnienie pomiędzy klasami a strukturami danych. Te pierwsze zawierają atrybuty i funkcje, a instancje klasy nazywamy obiektem. Zastosowanie klas pozwala na stworzenie interfejsu definującego pewne dane. Struktury danych służą natomiast do reprezentacji danych dowolnego typu a nie ich opisu.
-Dobry styl kodowania jest porównywany do prawidłowego stosowania interpunkcji. Jest możliwe nie stosowanie się do jej zasad, jednak przestrzeganie ich pozwala, aby w zapisie panował ład i porządek.
-W R dominują dwa style, które pomagają utrzymać dobry układ kodu. Jednym jest tidyverse style, a\(~\)drugim, wywodzącym się z poprzedniego, Google style. Istnieją przewodniki, które ułatwiają stosowanie się do zasad panujących w tych stylach. Style ustosunkowują się m.in. do stawiania spacji po przecinkach, przed operatorami matematycznymi oraz po nich, a także podkreślników w nazwach.
-Dodatkowo można zainstalować pakiety, które będą pomagać w utrzymaniu schludnego kodu: cleanr, stylerr, lintr.
Dane najczęściej są przedstawiane w postaci tabelarycznej. Jednak mogą być w tej tabeli różnie sformatowane. Wyróżnia się między innymi szeroką reprezentacje danych i wąską reprezentacje danych. W zależności od tego, co chcemy z nimi zrobić czasami trzeba przejść z jednej postaci do drugiej. Aby przetransformować dane korzysta się z funkcji z pakietów dplyr i tidyverse.
-O postaci szerokiej mówimy, gdy pojedyncza zmienna jest rozdzielona pomiędzy kilka kolumn. Różnicę najłatwiej jest pokazać na przykładzie. W tym celu wykorzystamy wbudowany zbiór danych sleep
zawierający informacje o wpływie dwóch leków nasennych na ilość przespanych godzin. Kolumna extra
zawiera informacje o ilości dodatkowo przespanych godzin.
-extra - | --group - | --ID - | -
---|---|---|
-0.7 - | --1 - | --1 - | -
--1.6 - | --1 - | --2 - | -
--0.2 - | --1 - | --3 - | -
--1.2 - | --1 - | --4 - | -
--0.1 - | --1 - | --5 - | -
-3.4 - | --1 - | --6 - | -
Dane są przedstawione w postaci wąskiej, każda zmienna jest przedstawiona w oddzielnej kolumnie. Teraz ‘rozbijmy’ kolumnę group
na group 1
i group 2
.
-ID - | --group 1 - | --group 2 - | -
---|---|---|
-1 - | --0.7 - | --1.9 - | -
-2 - | ---1.6 - | --0.8 - | -
-3 - | ---0.2 - | --1.1 - | -
-4 - | ---1.2 - | --0.1 - | -
-5 - | ---0.1 - | ---0.1 - | -
-6 - | --3.4 - | --4.4 - | -
-7 - | --3.7 - | --5.5 - | -
-8 - | --0.8 - | --1.6 - | -
-9 - | --0.0 - | --4.6 - | -
-10 - | --2.0 - | --3.4 - | -
Można zaobserwować, że wartości z kolumny extra
zostały wpisane w poszczególne komórki, a kolumna group
została podzielona na dwie oddzielne kolumny group 1
i group 2
. Tak sformatowane dane nazywamy szeroką reprezentacją danych.
Aby przejść z wąskiego formatu przedstawiania danych do szerokiego, można użyć funkcji spread()
z pakietu dplyr.
Funkcja spread(dataset,key,value)
przyjmuje trzy agrumenty:
dataset
- zbiór danych w formacie wąskim,
key
- kolumna (klucz) odpowiadająca kolumnie, która ma zostać rozłożona,
value
- kolumna, w której znajdują się wartości wypełniające nowe kolumny.
<- spread(sleep, group, extra)
- szeroka colnames(szeroka) = c("ID","group 1","group 2")
-kable_styling(kable(head(szeroka)), position = "center")
-ID - | --group 1 - | --group 2 - | -
---|---|---|
-1 - | --0.7 - | --1.9 - | -
-2 - | ---1.6 - | --0.8 - | -
-3 - | ---0.2 - | --1.1 - | -
-4 - | ---1.2 - | --0.1 - | -
-5 - | ---0.1 - | ---0.1 - | -
-6 - | --3.4 - | --4.4 - | -
Drugą opcją na uzyskanie tego samego rezultatu jest użycie funkcji pivot_wider
z pakietu tidyverse.
Funkcja przyjmuje dwa argumenty pivot_wider(names_from = name, values_from = value)
:
name
- nazwa kolumny, która ma zostać rozłożona,
value
- nazwa kolumny, w której znajdują się wartości.
%>%
- sleep pivot_wider(names_from = group, values_from = extra)
Można wrócić z postaci szerokiej do wąskiej. W tym celu należy użyć funkcji gather()
z pakietu tidyr.
Funkcja gather(dataset, key, value, other)
przyjmuje również trzy argumenty:
dataset
- zbiór danych w formacie szerokim,
key
- nazwy kolumn z kluczami,
value
- nazwy kolumn z wartościami,
other
- kolumny dataset
, które mają być zawarte w nowej tabeli.
Aby wrócić do postaci wąskiej nałóżmy funkcję gather
na wygenerowaną wcześniej tabele szeroka
.
kable_styling(kable(head(szeroka %>%
-gather(group, extra, -ID))),position = "center")
-ID - | --group - | --extra - | -
---|---|---|
-1 - | --1 - | --0.7 - | -
-2 - | --1 - | ---1.6 - | -
-3 - | --1 - | ---0.2 - | -
-4 - | --1 - | ---1.2 - | -
-5 - | --1 - | ---0.1 - | -
-6 - | --1 - | --3.4 - | -
Drugą funkcją, która umożliwia przejście z szerokiej reprezentacji danych do wąskiej jest funkcja pivot_longer
z pakietu tidyverse.
Funkcja pivot_longer(col_names, names_to = name, values_to = value)
przyjmuje trzy argumenty
col_names
- ciąg nazw kolumn, które chcemy złączyć,
name
- nazwa nowo powstałej kolumny,
value
- nazwa kolumny, w której pojawią się wartości.
kable_styling(kable(head(szeroka %>%
-pivot_longer(c("1", "2"), names_to = "group", values_to = "extra"))),
- position = "center")
Badanie eksploracyjne danych (ang. exploratory data analysis) dotyczy opisu, wizualizacji i badania zebranych danych bez potrzeby zakładania z góry hipotez badawczych. Badania ekploracyjne obejmują również wstępne sprawdzenie danych w celu skontrolowania założeń modeli statystycznych lub występowania błędów w danych (np. braków odpowiedzi).
-Dane tabelaryczne to dane, które mają postać tabeli. Tabela to struktura danych, która składa się z wierszy i kolumn. Każdy wiersz odpowiada pewnej obserwacji, której cechy zostały zapisane w kolejnych kolumnach.
-Zmienne, które opisują kolejne obserwacje możemy podzielić na:
-Zapoznając się z danymi chcielibyśmy sprawdzić wokół jakiej wartości są skupione oraz jak bardzo są zmienne wartości danej cechy.
-Miary lokacji (miary tendencji centralnej) pomagają nam umiejscowić dane na osi. Przykładami takich miar są:
-Natomiast miary rozrzutu dostarczają informacji jak bardzo zróżnicowane są obserwacje pod względem badanej cechy. Przykładami takich miar są:
-Wyróżniamy także miary asymetrii. Miary asymetrii mówią nam, czy większa część populacji klasuje się powyżej, czy poniżej przeciętnego poziomu badanej cechy. Asymetrię rozkładu można zbadać porównując średnią, dominantę i medianę.
-Podstawowymi funkcjami, które pomagają nam zapoznać się z danymi są funkcje:
-Natomiast podstawowymi funkcjami, które podsumowują kolejne kolumny są funkcje:
-\(\texttt{str}\) - zwraca strukturę danego obiektu. Wyświetla np. klasę obiektu, liczbę wierszy i kolumn, a także nazwę danej kolumny, typ wartości w niej zawartych, jak i kilka początkowych wartości.
\(\texttt{summary}\) - zwraca podsumowanie każdej kolumny. Dla zmiennych ciagłych wyznacza wartości tj.:
-Natomiast w przypadku zmiennych dyskretnych wyznacza liczbę obserwacji, które przyjmują daną wartość zmiennej.
\(\texttt{glimpse}\) - funkcja z pakietu \(\texttt{tidyverse}\) podobna do \(\texttt{str}\), ale stara się pokazać jak najwięcej danych. Wyświetla np. liczbę wierszy i kolumn, a także nazwę danej kolumny, typ wartości w niej zawartych oraz jak najwięcej wartości z tej kolumny.
2023-10-12
-Zaliczenie przedmiotu opiera się głównie na projekcie grupowym. Przykładowy projekt z poprzednich edycji: SpotifyViz.
-Autorzy poszczególnych rozdziałów:
-Dodatkowe rozdziały:
-Shiny jest pakietem R pozwalającym na tworzenie interaktywnych aplikacji webowych w łatwy i przystępny sposób. Aplikacja w shiny zbudowana jest z dwóch następujcych elementów:
-ui - user interface, czyli obiekt, w którym zawarty jest wygląd aplikacji,
server - funkcja organizująca działanie aplikacji.
Do uruchomienia aplikacji służy funkcja shinyApp(ui, server)
. Stworzenie dobrej i czytelnej aplikacji może znacznie ułatwić analizowanie danych.
W tej notatce zajmiemy się omówieniem elementów oraz podstawowych schematów budowy UI.
-library(shiny)
##
-## Dołączanie pakietu: 'shiny'
-## Następujący obiekt został zakryty _przez_ '.GlobalEnv':
-##
-## a
-library(shinyWidgets)
-library(shinydashboard)
##
-## Dołączanie pakietu: 'shinydashboard'
-## Następujący obiekt został zakryty z 'package:graphics':
-##
-## box
-Do budowania podstawowego interfejsu w shiny będziemy korzystać z funkcji fluidPage
, w której tworzymy cały UI. Wszystkie informacje o rodzajach wprowadznych danych, strukturze wyświetlanych danych oraz szeroko rozumianej estetyce aplikacji będą zawarte wewnątrz tej funkcji.
<- fluidPage(
- ui # coś
- )
Tym co jest bardzo ważne w UI jest oczywiście wygląd, a dokładniej mówiąc przejrzystość i czytelność, dlatego chcielibyśmy uporządkować wyświetlane elementy tak, aby umożliwić użytkownikowi intuicyjne korzystanie z aplikacji. Pakiet shiny oferuje wiele narzędzi pozwalających na zorganizowanie układu interfejsu zgodnie z naszymi oczekiwaniami.
-Przydadzą nam się do tego następujące funkcje:
-titlePanel
- funkcja tworząca panel tytułowy, w której podajemy tytuł aplikacji,
sidebarLayout
- funkcja organizująca wygląd strony jako mniejszy panel boczny po lewej stronie oraz większy panel po prawej stronie,
sidebarPanel
- funkcja, którą możemy umieścić w poprzedniej funkcji, aby uporządkować panel, w którym będziemy np. wprowadzać dane,
mainPanel
- funkcja, w której umieszczamy treści, które chcemy, aby znalazły się w panelu głównym,
tabsetPanel
- funkcja umożliwiająca organizowanie paska zakładek. Aby utworzyć zakładki w jej ciele używamy funkcji tabPanel
, w której umieszczamy dowolne treści, np. wykresy lub tabele.
Oprócz tego możemy bardziej modyfikować wygląd aplikacji dzięki funkcjom fluidRow
i column
pozwalającym na uporządkowanie obiektów odpowiednio w wierszach oraz kolumnach.
Układ strony należy oczywiście podporządkować temu jaką funkcję ma pełnić aplikacja, a także temu jaki rodzaj interakcji ma mieć z nią docelowo użytkownik. Interakcje użytkownika z aplikacją można intuicyjnie podzielić na to co zostaje do aplikacji wprowadzone (input) oraz to co ostatecznie w związku z tym aplikacja zwraca (output). Każdy input i output jest w kodzie identyfikowany dzięki nadanej mu przez nas nazwie. Wewnątrz fluidPage
możemy zawrzeć różne rodzaje inputów i outputów w zależności od rodzaju wprowadzanych/wyświetlanych danych.
textInput
- funkcja tworząca pole, w którym użytkownik może wprowadzić dowolny tekst,<- fluidPage(
- ui # Okienko do wpisywania tekstu
- textInput("nazwa_inputu_1", "Tekst wyświetlany w aplikacji")
- )
numericInput
- funkcja tworząca pole, w którym użytkownik może wprowadzić wartość liczbową,<- fluidPage(
- ui # Okienko do wpisywania liczb
- numericInput("nazwa_inputu_2", "Tekst wyświetlany w aplikacji",
- # Wartość domyślna
- value = 10)
- )
selectInput
- funkcja tworząca listę, z której użytkownik może dokonać wyboru - domyślnie parametr multiple
umożliwia wybór jednej pozycji z listy,<- fluidPage(
- ui # Możliwość wybrania z listy
- selectInput("nazwa_inputu_3", "Tekst wyświetlany w aplikacji",
- # Lista możliwości do wyboru
- choices = c("Wybór_1", "Wybór_2"))
- )
sliderInput
- funkcja tworząca suwak umożliwiający użytkownikowi wybór zakresu interesujących go wartości,<- fluidPage(
- ui # Suwak do wyboru wartości
- sliderInput("nazwa_inputu_4", "Tekst wyświetlany w aplikacji",
- # Wartość domyślna
- value = 1,
- # Wartość minimalna
- min = 0,
- # Wartość maksymalna
- max = 10)
- )
dateRangeInput
- funkcja tworząca pole wyboru zakresu interesujących dat.<- fluidPage(
- ui # Pole wyboru zakresu dat
- dateRangeInput("nazwa_inputu_5", "Tekst wyświetlany w aplikacji",
- # Data początkowa
- start = "2001-01-01",
- # Data końcowa
- end = "2010-12-31")
- )
Używanie funkcji wyświetlających outputy jest bardzo proste, ponieważ w UI decydujemy jedynie gdzie i jak wyswietlić output, który jest obiektem utworzonym wewnątrz funkcji server
na podstawie wprowadzonego przez użytkownika inputu.
textOutput
- funkcja wyświetlająca tekst,<- fluidPage(
- ui # Wyświetla tekst, który stworzyliśmy w serwerze pod daną nazwą
- textOutput("nazwa_outputu_1")
- )
tableOutput
- podstawowa funkcja wyświetlająca tabelę,<- fluidPage(
- ui # Wyświetla tabelę stworzoną w serwerze pod daną nazwą
- tableOutput("nazwa_outputu_2")
- )
DTOutput
- funkcja wyświetlająca interaktywną ramkę danych z użyciem pakietu data.table,<- fluidPage(
- ui # Interaktywna ramka danych z użyciem data.table
- ::DTOutput("nazwa_outputu_3")
- DT )
plotOutput
- funkcja wyświetlająca wykres.<- fluidPage(
- ui # Wyświetla wykres stworzony w serwerze
- plotOutput("nazwa_outputu_4",
- # Szerokość wykresu
- width = "100%",
- # Wysokość wykresu
- height = "400px")
- )
Oczywiście powyższe kody były jedynie fragmentami większej całości. Poniżej możemy zobaczyć przykładowy kod obrazujący strukturę budowy interfejsu. Rzeczą, o której należy pamiętać jest oddzielanie funkcji przecinkami.
-<- fluidPage(
- ui # Tytuł
- titlePanel("Tytuł"),
-
- # To co będzie wyświetlone z boku interfejsu
- sidebarLayout(
-
- # Panel boczny
- sidebarPanel(
-
- # Pierwszy input - wybór
- selectInput("nazwa_inputu_1", "Tekst wyświetlany w aplikacji",
- choices = c("Wybór_1", "Wybór_2")),
- # Drugi input - suwak
- sliderInput("nazwa_inputu_2", "Tekst wyświetlany w aplikacji",
- value = 1, min = 0, max = 10)
-
- ),
- # Główny panel
- mainPanel(
-
- # Tworzymy zakładki
- tabsetPanel(
-
- # Pierwsza zakładka - wykres
- tabPanel("Tytuł wykresu", plotOutput("nazwa_outputu_1")),
- # Druga zakładka - ramka danych
- tabPanel("Tytuł ramki", DT::DTOutput("nazwa_outputu_2"))
-
- )
- )
- ) )
Dodatkowo warto zdawać sobie sprawę, że po wprowadzeniu danych przez użytkownika outputy aktualizują się automatycznie, dlatego często przydatne jest programowanie reaktywne z funkcją observeEvent
oraz użycie actionButton
, który pozwala na wykonanie danego działania dopiero po kliknięciu odpowiedniego przycisku przez użytkownika.
Ostatecznie chcielibyśmy, aby aplikacja wyglądała bardziej estetycznie. Możemy do tego użyć kilku narzędzi. Po pierwsze możemy zmienić motyw naszej aplikacji.
-Z pomocą przychodzi nam funkcja shinythemes::themeSelector()
, którą musimy umieścić w naszym UI. Wtedy w naszej aplikacji pojawia się pole z możliwością wyboru motywu.
Gdy już wybierzemy ulubiony motyw zamieniamy poprzednią funkcję w UI na theme = shinythemes::shinytheme('NASZ_MOTYW')
i gotowe!
Poza tym Shiny umożliwia całkowitą customizację wyglądu aplikacji przy użyciu HTML, CSS oraz JavaScript.
-Ostatnim narzędziem, o którym warto pamiętać, jest shinyWidgetsGallery()
. Jest to bardzo użyteczna aplikacja stworzona w bibliotece shinyWidgets
, dzięki której możemy między innymi zobaczyć w praktyce działanie różnego typu inputów oraz kod umożliwiający użycie ich w aplikacji.
W tej notatce omówiliśmy podstawowe elementy pozwalające na zbudowanie interfejsu w shiny ale chcielibyśmy też dodać, że w poszukiwaniu bardziej zaawansowanych rozwiązań warto odwiedzić stronę https://shiny.rstudio.com/, gdzie można znaleźć dokumentację pakietu shiny, wiele przykładów oraz nieomówionych tu funkcji.
- -Shiny to biblioteka w R pozwalająca na budowanie interaktywnych aplikacji w prosty i szybki sposób. Aplikacja Shiny składa się z dwóch części, opisywanych w dwóch osobnych plikach: interfejs użytkownika (UI), czyli jak aplikacja będzie wyglądać u użytkownika oraz sposób przetwarzania danych (serwer). W tej pracy zajmiemy się stroną serwerową Shiny.
-Aplikacje Shiny zazwyczaj budujemy w sytuacjach, w których mamy dane, chcemy obliczyć pewne rzeczy i narysować odpowiednie wykresy. Użytkownik widzi efekt końcowy, czyli to jak zaprogramowaliśmy gdzie ma się wyświetlać wynik, natomiast w części serwerowej opisujemy jak ten wynik ma być obliczony. Jest to więc część zależna od pliku UI.
-Musimy więc w kodzie serwera zamieścić obiekty opisane w UI. Zauważmy, że tworzymy kod serwera jako funkcję od dwóch parametrów: input, output
. W środku serwera definiujemy zależności pomiędzy inputami
i outputami
.
Jedną z zalet Shiny jest interaktywność. Dzięki temu użytkownik może na bieżąco zmieniać parametry i generować nowe wykresy. Jednak generowanie kodu na nowo przy każdej zmianie danych nie zawsze jest pożądane. Ważnym pojęciem przy pisaniu strony serwerowej jest reaktywność (żródło infografiki: Shiny Cheat Sheet).
-Jeśli zmienna jest reaktywna, to znaczy że jakakolwiek jej zmiana powoduje ponowne uruchomienie funkcji z nią powiązanych. Do budowania reaktywnych wyrażeń używamy funkcji reactive()
. Taka zmienna jest liczona tylko raz i wyrażenia z nią związane używają tej wartości aż do momentu aktualizacji wybranego przez użytkownika. Z pojęciem reaktywności wiąże się kilka ważnych funkcji:
reactiveValues(...)
, które tworzy listą reaktywnych zmiennych,isolate(expr)
- zapobiega zależności od reaktywnych zmiennych,render*()
- funkcje tworzące obiekty do wyświetlenia, które zmieniają się wraz z reaktywnymi zmiennymi,observeEvent(...)
- gdy nie chcemy aby model od razu się zaktualizował przy zmianie danych, a przy jakiejś określonej akcji,reactive()
- tworzy reaktywne wyrażeniaeventReactive
- tworzy reaktywne wyrażenia, które nie zależą od wszystkich reaktywnych zmiennych, a zależą jedynie od akcji wymienionych w pierwszym argumencie.Jednym z ważnych elementów przekazywania ciekawych informacji oraz ich analizy jest przedstawienie graficzne interesujących nas danych. W R istnieje kilka sposobów na wizualizację danych. Jednym z nich jest korzytanie z narzędzi oferowanych przez pakiet ggplot2. Bibiloteka ggplot2 oprócz zwykłych funkcji plotowania, implementuje także gramatykę grafiki, co pozwala na wykonanie prawie każdego rodzaju (statystycznej) wizualizacji danych.
-Powyżej wspomnieliśmy o gramatyce grafiki. Dla dokładniejszego uporządkowania wiedzy przypomnijmy, że gramatyka grafiki daje nam możliwość zadawania odpowiednich parametórw dla wszystkich linii, słów, strzałek, itp., które połączone tworzą wykres. Dodatkowo możemy m.in. zmieniać układ współrzędnych, czy korygować położenie każdego obiektu znajdującego się na wykresie. Możliwości jakie oferuje nam gramatyka grafiki będą przedstawione dokładniej w dalszej części notatki.
-Na początku, aby móc tworzyć wizualizacje, musimy załadować pakiet oraz bibilotekę ggplot2. Warto zwrócić uwagę, że ggplot2 posiada również szereg wbudowanych zestawów danych. Aby pokazać możliwości jakie oferuje nam ggplot, przeprowadzimy symulację danych mpg dostępnych w R.
-library(ggplot2)
-head(mpg)
## # A tibble: 6 × 11
-## manufacturer model displ year cyl trans drv cty hwy fl class
-## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
-## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
-## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
-## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compact
-## 4 audi a4 2 2008 4 auto(av) f 21 30 p compact
-## 5 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
-## 6 audi a4 2.8 1999 6 manual(m5) f 18 26 p compact
-Składnia wykresów w ggplot polega na warstwowym budowaniu wykresów.
-Uwaga!
-Do dodawania nowych warstw do wykresu używamy symbolu “+” .
-# Budujemy podstawę wykresu, określając z jakich danych będziemy korzytsać
-ggplot(mpg)
# Mapujemy dane ( na osiach pojawiły się odpowiednie podziałki)
-ggplot(mpg , aes( x = displ, y = hwy))
# Określamy styl wykresu, dzięki czemu dostemy wykres odpwiednich zależności
-ggplot(mpg , aes( x = displ, y = hwy))+
-geom_point()
# Personalizujemy wykres poprzez dodanie tytułu oraz określenie motywu wykresu
-ggplot(mpg , aes( x = displ, y = hwy))+
-geom_point()+
- ggtitle("disp vs hwy")+
- theme_bw()
Mapowanie danych jest estetyką, która mówi ggplot’owi, jakie zmienne powinny znajdować się na osi x oraz y. Dodatkowo możemy wpływać na cechy wizualne danych, takie jak kolor ( color = ), kształt ( shape = ), czy przezroczystość ( alpha = ). Wszystkie estetyki dla podziałki wykresu są określone w wywołaniu funkcji aes().
-Uwaga!
-Każda warstwa geom może mieć swoją własną specyfikację aes. Możemy zdecydować, czy na wykresie geom_point punkty mają być zaznaczone jako koła, czy kwadraty.
-# Punkty na wykresie będą kwadratami
-ggplot(mpg, aes(x = displ, y = hwy)) +
-geom_point(shape = 0)+
- ggtitle("displ vs hwy")+
- theme( axis.title = element_text(size = 1))+
- theme_bw()
# Punkty na wykresie to czerwone kropki
-ggplot(mpg, aes(x = displ, y = hwy)) +
-geom_point(color = "red")+
- ggtitle("displ vs hwy")+
- theme_bw()
Za pomocą ggplot2 możemy stworzyć prawie każdy rodzaj wykresu. W tym celu musimy zadać typ wykresu jaki nas interesuje. Ggplot2 daje możliwość stworzenia wykresu:
-oraz wielu innych, które powstają m.in. przez zastosowanie funcji: geom_area, geom_density, geom_dotplot, geom_qq, geom_smooth.
-Uwaga!
-Poniżej przedstawione są dwa przykładowe typy wykresów. Pierwszy narysowany przy użyciu funkcji geom_smooth, która służy do rysowania wygładzonych linii, np. dla prostych trendów. Drugi wykres powstał przy zastosowaniu funkcji geom_histogram. -
-W pakiecie ggplot2 bardzo prosto możemy łączyć ze sobą różne geometrie na jednym wykresie. Wystarczy wstawić znak “+” pomiędzy odpowiednimi funkcjami.
-ggplot(mpg , aes( x = displ, y = hwy))+
-geom_point()+
- geom_smooth()+
- ggtitle("Multiple geomteries")+
- theme_bw()
Domyślnym systemem współrzędnych dla ggplot2 jest kartezjański układ współrzędnych. W zależności od danych na jakich działamy, może się okazać, że pokazanie danych w innym układzie współrzędnych, wpłynie na lepszy odbiór informacji z wykresu.
-Funkcjami, które odpowiadają za przekształcenie układu współrzędnych są m.in.
-Każda geometria w ggplot2 ma ustawione domyślne położenie różnych elementów na wykresie względem siebie. Różne opcje ustawienia położenia są dobrze widoczne na wykresach słupkowych. Zacznijmy od stworzenia zwykłego wykresu słupkowego, bez żadnych dodatkowych funkcji.
- -Jeżeli teraz do mapowania dodamy opcję fill = dvr, to każdy prostokąt będzie reprezentował kombinację wartości class oraz dvr.
- -Takie przedstawienie danych nie dla każdego może być czytelne, dlatego możemy skorzystać z opcji position, która przyjmuje m.in. argumenty: “dodge” i “fill”.
- -Jedną z możliwości jaką oferuje nam pakiet ggplot2 jest prosta zmiana skali na osiach wykresu. Podstawowymi funkcjami, które to umożliwiają są:
-W ggplot2 z łatwością także dodamy etykiety tekstowe oraz adnotacje. Do wykresu możemy dodać tytuł oraz nazwy osi korzystając m.in. z funkcji labs().
-ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
-geom_point() +
- labs(title = "Fuel Efficiency by Engine Power",
- x = "Engine power",
- y = "Fuel Efficiency",
- color = "Car Type")
Theme to dobry sposób na dostosowanie odpowiedniego tytułu, etykiet, czcionek, tła, legendy, czy lini siatki na wykresie. Możemy skorzystać z jednego z dostępnych motywów, takich jak theme_bw(), czy theme_minimal(). Istnieje możliwość zastosowania wielu dostępnych opcji tak, aby odpowiednie elementy wykresu wyglądały tak, jak chcemy. Podstawowymi funkcjami, jakie warto znać są m.in. legend.position, dzięki której możemy ustalić pozycję legendy wykresu, axis.text, która umożliwia nam ustawienie czcionki na wykresie oraz ustalenie jej wielkości czy koloru. Przydatną funkcją pochodzącą z rodziny theme jest ‘theme(axis.text.x = element_text(angle = 90))’, która obraca nazwy znajdujące się na osi x, dzięki, czemu stają się one czytelniejsze.
-Ostatnim z podstawowych funkcji jakie oferuje pakiet ggplot2 jest facets.
-Panele to sposoby grupowania wykresu danych w wiele różnych części ze względu na zadaną zmienną. Możemy korzystać z funkcji:
-ggplot(mpg, aes(x = displ, y = hwy)) +
-geom_point() +
- facet_grid(~ class)
Uwaga!
-Aby zadać względem, której zmiennej chcemy grupować, w funkcji ‘facet_’ po znaku “~”, podajemy nazwę tej zmiennej.
-Kiedy korzystamy z funkcji tworzącej panele, automatycznie wszytskie wykresy będą pokazane w układzie współrzędnych dopasowanym do wszytkich okienek. Istnieje jednak możliwość dopasowania układu współrzędnych do każdego panelu osobno. W tym celu możemy wykorzystać funcję ‘scale = “free”’.
- -