---
title: "Zaawansowane typy danych.ipynb"
author: "Bartosz Maćkiewicz"
subtitle: Statystyka I z R
output:
  html_document: default
  pdf_document: default
---

## Zaawansowane typy danych

W tej części kursu będziemy omawiać bardziej zaawansowane typy danych, z którymi możemy pracować w R.

### Dygresja: `dolna_granica:górna_granica`

Na początek nauczymy się tworzenia wektorów liczb całkowitych (`integer`) za pomocą konstrukcji `dolna granica:górna granica`.

Jest to bardzo często wykorzystywany sposób, który pojawiać będzie się przez cały kurs.

```{r}
dwadziescia_liczb <- 1:20 # Tworzymy wektor typu integer z liczbami od 1 do 20
dwadziescia_liczb # sprawdzamy czy rzeczywiście się utworzył
class(dwadziescia_liczb) # sprawdzamy jego typ
```

Jeżeli jaki pierwszą podamy mniejszą liczbę, to R z takim wypadkiem sobie poradzi i również utworzy ciąg liczb całkowitych.

```{r}
5:1
```

Jeżeli interesują nas bardziej wyrafinowane sekwencje liczb, to powinniśmy zainteresować się funkcja `seq`. Poniżej znajduje się przykład polecenia, tworzącego sekwencję liczb całkowitych od 5 do 56, w ktorej każda kolejna liczba jest większa od poprzedniej o 3. Więcej o tej funkcji można znaleźć w dokumentacji (`?seq`)

```{r}
seq(from = 5, to = 55, by = 3)
```


## Macierze

Utwórzmy też macierz o wymiarach 4x5. Kolejne liczby z wektora `dwadziescia_liczb` wypełniają po kolei kolumny naszej macierzy. Zrobimy to za pomocą funkcji `matrix`.

```{r eval = F}
matrix(dane, wiesze, kolumny)
```

- `dane` - wartości, którymi chcemy wypełnić macierz
- `wiesze` - liczba wierszy
- `kolumny` - liczba kolumn

Warto w tym miejscu zwrócić uwagę na dwa fakty.

1. R domyślnie wypełnia macierze kolumnami
2. Jeżeli jakaś funkcja przyjmuje jako argumenty wymiary jakiejś dwuwymiarowej struktury danych, to najpierw podaje się liczbę wierszy a dopiero potem liczbę kolumn. Oto mnemotechniczna rymowanka, która pozwala zapamiętać to zachowanie: *wiersze pierwsze*.

```{r}
macierz <- matrix(dwadziescia_liczb, 4,5)
macierz 
```

Za pomocą argumentu `byrow` możemy jednak wypełniać macierz wierszami.

```{r}
macierz_wiersze <- matrix(dwadziescia_liczb, 4,5, byrow = TRUE)
macierz_wiersze
```

Do macierzy możemy dodawać nowe wiersze i kolumny za pomocą funkcji `cbind` i `rbind`.

```{r}
print(cbind(macierz_wiersze, c(1000,2000,3000,400))) # analogicznie rbind
```

```{r}
print(rbind(macierz_wiersze, macierz_wiersze)) # możemy nawet "złączyć" dwie macierze w ten sam sposób
```

Na macierzach podobnie jak na wektorach możemy wykonywać operacje element-po-elemencie, na przykład mnożenie.

```{r}
macierz * macierz_wiersze # mnożenie R-owe, "element-po-elemencie"
```

Możemy również wykonywać operacje algebraiczne na macierzach.

```{r}
a <- matrix(c(2,4,6,8,10,12,14,18), 2,4)
a
```

```{r}
b <- matrix(c(9,8,7,6,5,4,3,2), 4,2)
b
```

```{r}
a %*% b # iloczyn macierzy
```

Inne przydatne podstawowe operacje:

- `t` - transpozycja

```{r}
# inny sposób tworzenia macierzy za pomocą funkcji cbind (*column bind*)
macierz_2 <- cbind(30:40, 25:35, 130:140) 
t(macierz_2) # Transpozycja
```

- `rowSums`, `colSums`, `rowMeans`, `colMeans` - sumy/średnie kolumnami/wierszami

```{r}
rowMeans(macierz_2) # analogiczne colMeans
colSums(macierz_2) # analogicznie rowSums
```

O wymiarach macierzy możemy się dowiedzieć za pomocą funkcji `dim`, `ncol`, `nrow`

```{r}
dim(macierz_2) # wymiary
ncol(macierz_2) # liczba kolumn
nrow(macierz_2) # liczba wierszy
```

Dla naszych celów ta wiedza powinna wystarczyć, statystycy z socjologii prosili jednak o podstawy algebry w R. Polecam więc zajrzenie w stosownym czasie do np. [Algebra w R](https://www.r-bloggers.com/quick-review-of-matrix-algebra-in-r/) (polecam również samą stronę!)

## Listy

Listy w przeciwieństwie do wektorów przechowują sekwencje wartości różnych typów. Możemy w niej przechowywać wektory różnych typów o różnej długości a nawet inne listy. W tym sensie są podobne do list z niektórych innych języków programowania. Listy tworzymy za pomocą funkcji `list`.

```{r}
lista <- list(c(1,2,3,4,5), # pierwszy element: wektor typu `integer`
              c('Adam', 'Marysia', 'Zosia', 'Tosia'), # drugi element: wektor typu `character`
              TRUE, # trzeci element: wektor typu `logical`
              TRUE, # czwarty element: wektor typu `logical`
              list( # piąty element: lista
                c(-1,-2,-3) # pierwszy element: wektor typu `numeric`
                )
              )
lista
```

Elementom listy możemy nadawać nazwy. Dlatego w niektórych sytuacjach możemy traktować je jak słowniki z innych języków programowania, przechowujące pary klucz-wartość.

Nazwane listy również tworzymy przy pomocy funkcji `list`.

```{r}
lista_nazwana <- list(liczby_od_jeden_do_piec = c(1,2,3,4,5),
                      imiona = c('Adam', 'Marysia', 'Zosia', 'Tosia'),
                      czy_r_jest_fajny = TRUE,
                      czy_zajecia_sa_fajne = TRUE,
                      lista_zagniezdzona = list(c(-1,-2,-3)))
lista_nazwana
```

Do list wrócimy jeszcze kiedy będziemy mówić o indeksowaniu.

## Ramki danych (*data frame*)

Ramki danych (*data frame*) są typem danych, z którym w praktyce będziemy pracować najczęściej. O ramkach danych można myśleć jako np. o tabelach Excela, w której każdy wiersz reprezentuje jedną obserwację.

Tworzenie ramek danych jest dość podobne do tworzenia list. To, co w listach było nazwami elementow, w przypadku ramek danych będzie nazwami kolumn. Poniżej znajduje sie kilka przydatnych sposobów tworzenia ramek danych. Na razie pomijamy najczęściej wykorzystywany w praktyce sposób. Z reguły bowiem ramki danych będziemy tworzyć wczytując dane z pliku. Tym jednak zajmiemy się później. 

Podstawowy sposób stworzenia ramki danych wygląda tak:

```{r}
x <- c('Kasia', 'Zosia', 'Marysia', 'Tosia', 'Zbyszek')
y <- factor(c('F', 'F', 'F', 'F', 'M'), levels = c('F','M'))
z <- c(2, 4, 5, 8, 2)

# ramki danych tworzy się w zasadzie tak samo jak listy
dane <- data.frame(imie = x,
                  plec = y,
                  liczba_jabluszek = z
                  ) 
dane
```

Jeśli mamy listę, której elementy są wektorami równej długości, to możemy przekonwertować ją na ramkę danych.

```{r}
lista_nie_ramka <- list(imie = x,
                        plec = y,
                        liczba_jabluszek = z)
data.frame(lista_nie_ramka) 
```

W ramce danych nie tylko kolumny mogą mieć swoją nazwę. Możemy ustalić, że również każdy wiersz będzie miał nazwę. Uczynimy to przekazując funkcji `data.frame` argument `row.names` w postaci wektora z nazwami.

```{r}
data.frame(plec = y,
           liczba_jabluszek = z,
           row.names = x)
```

Do postaci ramki danych możemy przekonwertować również macierz. Czasami jest to przydatne. Służy do tego funkcja `as.data.frame`.

```{r}
ramka_z_macierzy <- as.data.frame(macierz) # możemy utworzyć z macierzy
ramka_z_macierzy
```

Powiedzieliśmy sobie, że w ramkach danych kolumny oraz wiersze mogą mieć nazwy. Jeśli chodzi o kolumny, to funkcji `colnames` zwraca wektor z nazwami kolumn ramki danych.

```{r}
dane
colnames(dane)
```

Za pomocą tej samej funkcji możemy zmienić też nazwy. Wystarczy, że nadpiszemy zwrócony przez funkcję `colnames` wektor swoim własnym wektorem, w którym zawrzemy nowe nazwy kolumn. To samo możemy zrobić również z nazwami wierszy, korzystając w funkcji `rownames`.

```{r}
ramka_z_macierzy
# Zastępujemy domyśle nazwy kolumn (V1, V2, V3...) swoimi własnymi.
colnames(ramka_z_macierzy) <- c('Jeden', 'Dwa', 'Trzy', 'Cztery', 'Pięć')
ramka_z_macierzy
```
