Automatyzacja wizualizacji danych

Przetwarzanie danych

Author

Krzysztof Dyba

Dane

Dane to fakty, które są gromadzone, obserwowane lub mierzone, a następnie wykorzystywane do analizy i podejmowania decyzji. Wyrażane są w różnych formach jako tekst, liczby, symbole, obrazy czy dźwięk. Dane w stanie początkowym nie mają kontekstu (jest to tylko zbiór pewnych faktów). Aby były użyteczne, muszą zostać przetworzone i zinterpretowane. Dane mogą być pozyskiwane z różnych źródeł, np. czujników, ankiet, pomiarów terenowych czy eksperymentów.

flowchart LR
    A[Dane] -->|Przetwarzanie| B[Informacja]
    B -->|Analiza| C[Wiedza]

Podział danych ze względu na typ:

  • Jakościowe – dane kategoryczne przedstawiające cechy lub atrybuty, np. kolory, klasy pokrycia terenu, nazwy.
  • Ilościowe – dane numeryczne, które można zmierzyć lub policzyć, np. temperatura, wysokość terenu, wiek.

Struktury danych

Struktura danych to format organizowania, przetwarzania i przechowywania danych. Jest to sposób na uporządkowanie danych w pamięci komputera lub na dysku, tak aby można było z nich efektywnie korzystać. Różne rodzaje struktur danych sprawdzają się w różnych zadaniach. Wybór właściwej dla danej sytuacji jest kluczową częścią programowania i tworzenia efektywnych algorytmów.

Język R oferuje rozmaite struktury danych, różniące się od siebie liczbą wymiarów oraz jednolitością przechowywanych elementów.

Struktura danych Liczba wymiarów Czy jednolity typ?
Wektor 1 Tak
Czynnik 1 Tak
Lista * Nie
Macierz 2 Tak
Ramka danych 2 Nie
Tablica \(n\) Tak

Wektor

Wektor (vector) – jednowymiarowa i jednolita struktura danych zawierająca elementy tego samego typu danych (liczba, ciąg znaków, wartość logiczna). Do tworzenia wektorów służy funkcja c().

# wektor numeryczny
v =  c(1, 3.14, -10)
typeof(v)
[1] "double"
# wektor tekstowy
v =  c("okno", "butelka", "Tomek")
typeof(v)
[1] "character"

Czynnik

Czynnik (factor) – jednowymiarowa i jednolita struktura danych reprezentująca dane kategoryczne (np. grupy czy klasy). Kategorie mogą być uporządkowane (stopniowane) według określonej kolejności (np. niski < średni < wysoki). Czynniki są przechowywane jako liczby całkowite z odpowiednimi etykietami. Do tworzenia czynników służy funkcja factor().

fct = factor(c("czerwony", "zielony", "zielony", "niebieski", "czerwony"))
# liczba wszystkich elementów w wektorze
length(fct)
[1] 5
# liczba kategorii
nlevels(fct)
[1] 3
# wyświetl kategorie
levels(fct)
[1] "czerwony"  "niebieski" "zielony"  

Lista

Lista (list) – jednowymiarowa struktura danych, która może zawierać elementy różnych typów danych. Jest także rekursywna, co oznacza, że może przechowywać inne struktury danych. Do tworzenia list służy funkcja list().

lst = list(imie = "Ania", wiek = 25, oceny = c(4, 4, 5), czy_student = TRUE)
lst
$imie
[1] "Ania"

$wiek
[1] 25

$oceny
[1] 4 4 5

$czy_student
[1] TRUE

Macierz

Macierz (matrix) – dwuwymiarowa i jednolita struktura danych zawierająca elementy tego samego typu danych. Do tworzenia macierzy służy funkcja matrix().

mat = matrix(1:9, ncol = 3)
mat
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

Ramka danych

Ramka danych (data frame) – dwuwymiarowa struktura danych, w której każda kolumna może zawierać różne typy. Jest najpopularniejszą strukturą do reprezentacji danych tabelarycznych na wzór arkuszu kalkulacyjnego. Każdy wiersz reprezentuje pojedynczą obserwację (rekord), natomiast kolumny reprezentują zmienne (atrybuty). Znajomość ramek danych jest absolutnie niezbędna do przeprowadzania wszelkiego rodzaju analiz danych! Do tworzenia ramek danych służy funkcja data.frame().

df = data.frame(
  imie = c("Ania", "Andrzej"), 
  wiek = c(25, 30),
  miasto = c("Warszawa", "Kraków")
)
df
     imie wiek   miasto
1    Ania   25 Warszawa
2 Andrzej   30   Kraków

Tablica

Tablica (array) – wielowymiarowa i jednolita struktura danych zawierająca elementy tego samego typu danych. Do tworzenia tablicy służy funkcja array().

# tablica jednowymiarowa (12 elementów)
arr = array(1:12, dim = 12)
arr
 [1]  1  2  3  4  5  6  7  8  9 10 11 12
# tablica trójwymiarowa (2x3x2)
arr = array(1:12, dim = c(2, 3, 2))
arr
, , 1

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

, , 2

     [,1] [,2] [,3]
[1,]    7    9   11
[2,]    8   10   12

Przetwarzanie danych tabelarycznych

Pakiet dplyr (z ekosystemu tidyverse) jest jednym z najpopularniejszych narzędzi do przetwarzania danych. Zapewnia on spójny i czytelny zestaw funkcji do wykonywania operacji, takich jak filtrowanie, wybieranie, grupowanie, zestawianie czy łączenie zbiorów danych.

Funkcja Opis
filter() Filtrowanie wierszy na podstawie warunku
select() Selekcja określonych kolumn
arrange() Sortowanie wierszy
mutate() Tworzenie lub modyfikacja kolumn
summarise() Obliczenie statystyk opisowych
group_by() Grupowanie danych
join() Łączenie danych z różnych tabel

Nie są to jednak wszystkie funkcje (pozostałe znajdziesz w dokumentacji).

Rozpocznijmy od zainstalowania pakietu dplyr.

install.packages("dplyr")

Następnie musimy go załadować do sesji używając funkcji library().

library("dplyr")

Do analizy wykorzystamy wbudowany zbiór danych mtcars, który zawiera informacje o 32 różnych modelach samochodów z magazynu Motor Trend US z 1974 r. W zbiorze znajduje się 11 zmiennych (kolumn) związanych z osiągami i konstrukcją tych samochodów. Dokumentację można sprawdzić używając ?mtcars.

# wczytanie danych
dane = mtcars

Filtrowanie

Funkcja filter() umożliwia wybieranie wierszy na podstawie określonych warunków. W tym celu można użyć różnych operatorów porównawczych (==, !=, >, <, >=, <=) i logicznych (&, |, !) oraz funkcji pomocniczych (all(), any(), is.na(), %in%).

# wybierz samochody, które mają 4 cylindry
filter(dane, cyl == 4)

# wybierz samochody, które mają 4 lub 6 cylindrów
filter(dane, cyl %in% c(4, 6))

# wybierz samochody, które mają więcej niż 100 koni mechanicznych
filter(dane, hp > 100)

# wybierz samochody spełniające dwa warunki (koniunkcja)
filter(dane, cyl == 4 & mpg > 25)

Selekcja

Funkcja select() pozwala wybrać określone kolumny z ramki danych.

# wybierz tylko dwie kolumny
select(dane, mpg, cyl)

# wybierz kolumny według zakresu
select(dane, mpg:hp)

# wykluczanie kolumn
select(dane, -wt, -qsec)

Dodatkowo dostępne są również funkcje pomocnicze, które ułatwiają selekcję kolumn:

  • starts_with() – wybiera kolumny, które zaczynają się od określonego prefiksu.
  • ends_with() – wybiera kolumny, które kończą się określonym sufiksem.
  • contains() – wybiera kolumny, które zawierają określony ciąg znaków.
  • matches() – wybiera kolumny, które pasują do wyrażenia regularnego (regex).
  • everything() – wybiera wszystkie pozostałe kolumny (jest to przydatne do zmiany kolejności kolumn w ramce danych).
# wybierz kolumny, które rozpoczynają się na "d"
select(dane, starts_with("d"))

# wybierz kolumny, które kończą się na "p"
select(dane, ends_with("p"))

# wybierz kolumny, które zawierają "ar"
select(dane, contains("ar"))

Sortowanie

Funkcja arrange() umożliwia sortowanie wierszy w kolejności rosnącej (domyślnie) lub malejącej na podstawie jednej lub więcej kolumn.

# sortowanie rosnące
arrange(dane, mpg)

# sortowanie malejące
arrange(dane, desc(mpg))

Tworzenie lub modyfikacja

Funkcja mutate() umożliwia dodawanie nowych kolumn lub zmianę istniejących.

# obliczenie kilometrów na litr benzyny
mutate(dane, kpl = mpg * 0.425)

# obliczenie współczynnika mocy do wagi 
mutate(dane, power_to_weight = hp / wt)

Statystyki opisowe

Funkcja summarise() umożliwia obliczanie statystyk opisowych, np. średnia, mediana czy liczba wystąpień.

# średnia
summarise(dane, mean_mpg = mean(mpg))

# mediana
summarise(dane, median_mpg = median(mpg))

# wartości unikalne
summarise(dane, cyl_groups = n_distinct(cyl))

# wiele statystyk
summarise(
  dane,
  mean_mpg = mean(mpg),
  sd_mpg = sd(mpg),
  min_mpg = min(mpg),
  max_mpg = max(mpg),
  n = n() # liczba wierszy
)

Grupowanie

Funkcja group_by() umożliwia grupowanie danych według jednej lub więcej kolumn, i wykonywanie operacji w obrębie każdej grupy. Jest ona często łączona z funkcją summarise().

grupy = group_by(mtcars, cyl)
summarise(grupy, 
          mean_mpg = mean(mpg),
          count = n())
# A tibble: 3 × 3
    cyl mean_mpg count
  <dbl>    <dbl> <int>
1     4     26.7    11
2     6     19.7     7
3     8     15.1    14

Łączenie tabel

Przetwarzanie potokowe

Przetwarzanie potokowe w kontekście analizy danych odnosi się do organizacji przepływu pracy w sposób sekwencyjny. Oznacza to, że dane są przetwarzane przez serię etapów (funkcji), w których wynik jednego etapu służy jako wejście do kolejnego. Zastosowanie operatora potoku (przepływu) sprawia, że kod jest bardziej czytelny, eliminując potrzebę stosowania zmiennych pośrednich i wyraźnie pokazując kolejność wykonywanych operacji.

W R od wersji 4.1 wbudowanym operatorem potoku jest |>. Do jego zapisu można wykorzystać skrót klawiszowy CTRL + SHIFT + M, jednak wymaga to zaznaczenia opcji Use native pipe operator (zakładka Code > Editing) w RStudio.

dane |>
  filter(mpg > 25) |>
  select(mpg, cyl, hp) |>
  arrange(desc(mpg))
                mpg cyl  hp
Toyota Corolla 33.9   4  65
Fiat 128       32.4   4  66
Honda Civic    30.4   4  52
Lotus Europa   30.4   4 113
Fiat X1-9      27.3   4  66
Porsche 914-2  26.0   4  91

Zadanie

W pakiecie nycflights13 znajdziesz zbiór danych flights. Zapoznaj się z jego dokumentacją i wykonaj następujące zadania używając pakietu dplyr:

  1. Wczytaj ten zbiór danych i dokonaj jego inspekcji:
    • sprawdź liczbę obserwacji i zmiennych,
    • wyświetl nazwy kolumn oraz ich typy,
    • wyświetl pierwsze kilka wierszy zbioru,
    • sprawdź liczbę brakujących wartości w każdej kolumnie.
  2. Dokonaj analizy danych:
    • 2.1. Oblicz liczbę odwołanych lotów. Przyjmij, że lot odwołany to taki, który nie posiada zapisanego czasu odlotu.
    • 2.2. Oblicz średnie opóźnienie odlotów na podstawie wszystkich lotów.
    • 2.3. Znajdź 10 lotów do Chicago (ORD) o najkrótszym czasie trwania.
    • 2.4. Zidentyfikuj loty, dla których stosunek czasu lotu do odległości był największy.
    • 2.5. Dodaj nową kolumnę do ramki danych reprezentującą średnią prędkość lotu. Dokonaj konwersji jednostek do \(km/h\).
    • 2.6. Pogrupuj dane według lotniska początkowego i oblicz średnie opóźnienie odlotu dla każdego z nich. Uporządkuj wyniki w kolejności malejącej według opóźnienia. Które lotnisko ma największe średnie opóźnienie?
    • 2.7. Pogrupuj dane według przewoźników i wskaż tych, którzy wykonali ponad 10 tysięcy lotów. Który przewoźnik wykonał najwięcej lotów?
    • 2.8. Pogrupuj dane według przewoźników i oblicz średnie opóźnienie odlotu dla każdego z nich. Połącz z danymi zawierającymi pełne nazwy linii lotniczych. Znajdź linię lotniczą o najgorszych wynikach.
    • 2.9. Pogrupuj dane według miejsca docelowego, oblicz średnie opóźnienie przylotu i wyświetl 10 miejsc z największym opóźnieniem. Podaj pełne nazwy lotnisk.
    • 2.10. Pogrupuj dane według miesięcy i oblicz średnie opóźnienie odlotu. Czy istnieją jakieś zauważalne wzorce sezonowe?
  3. Sformułuj własne pytanie badawcze, na które udzielisz odpowiedzi wykorzystując niniejszy zbiór danych. Wykonaj odpowiednią analizę, krótko zinterpretuj otrzymane wyniki oraz przedstaw finalny wniosek. Przykładowo pytanie może dotyczyć wpływu warunków atmosferycznych na opóźnienia lub zmienności lotów w ujęciu czasowym.