= 10 # liczba
x = "Tomek" # tekst imie
Wstęp do programowania
Typy i struktury danych
R to interpretowany język programowania wysokiego poziomu wykorzystywany przede wszystkim do przetwarzania, analizy i wizualizacji danych. Jest powszechnie używany zarówno w środowisku akademickim, jak i w przemyśle, szczególnie w takich dziedzinach jak statystyka, uczenie maszynowe, systemy informacji geograficznej czy bioinformatyka.
Cechy języka R:
- darmowy i otwarty,
- język interpretowany (kod wykonywany jest linia po linii, bez potrzeby kompilacji),
- język wysokiego poziomu (pominięcie aspektów związanych z zarządzaniem pamięcią),
- dynamiczne typowanie (zmienne nie wymagają jawnych deklaracji przed użyciem),
- wsparcie dwóch paradygmatów programowania, tj. obiektowego i funkcjonalnego,
- duży ekosystem (biblioteki, wsparcie, tutoriale),
- indeksowanie od 1,
- zwektoryzowane operacje (brak konieczności pisania pętli).
Zmienne
Do przypisania wartości zmiennej można wykorzystać dwa operatory: <-
oraz =
. Są między nimi pewne różnice, jednakże dla spójności z innymi językami programowania można korzystać z operatora =
w następujący sposób:
Znak #
służy do komentowania kodu. Wartościowe i zwięzłe komentarze sprawiają, że kod staje się zrozumiały.
Utworzone zmienne można wyświetlić wywołując bezpośrednio stworzony obiekt lub używając funkcji print()
.
x
[1] 10
print(imie)
[1] "Tomek"
Typy danych
Typ danych definiuje rodzaj wartości, jaką zmienna może przechowywać, oraz operacje, jakie można na niej wykonywać. Możemy wyróżnić następujące podstawowe typy danych:
- numeryczny numeric:
- liczby całkowite integer (np. -10, 0, 10),
- liczby zmiennoprzecinkowe double (np. 0.01, 21.37),
- tekstowy character (np. “Ala ma kota.”, ‘rower’),
- logiczny logical (TRUE, FALSE).
Do sprawdzenia typu danych służy funkcja typeof()
.
typeof(10.1)
[1] "double"
typeof(10)
[1] "double"
typeof("Tomek")
[1] "character"
typeof(TRUE)
[1] "logical"
Wartości logiczne TRUE
i FALSE
odpowiadają kolejno wartościom binarnym 1 i 0, w związku z czym można wykorzystać je w obliczeniach numerycznych (najczęściej do sumowania wystąpień wartości TRUE
).
Uwaga! Domyślnie wszystkie liczby traktowane są jako zmiennoprzecinkowe, tak jak w powyższym przykładzie 10 posiada typ double
, mimo iż jest całkowita. Aby traktować ją jako całkowitą należy do liczby dodać literę L
.
typeof(10L)
[1] "integer"
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.
Wektor
Wektory (vector) stanowią najprostszą strukturę danych. Są to jednowymiarowe tablice, które mogą przechowywać zbiór elementów tego samego typu danych (np. tylko liczby, tylko tekst lub tylko wartości logiczne). Wektory są podstawą bardziej złożonych struktur danych, takich jak macierze czy ramki danych.
Do tworzenia wektorów wykorzystuje się funkcje c()
(combine) łączącą elementy.
# stworzenie wektora liczbowego
= c(1, 2, 3, 4, 5)
vec vec
[1] 1 2 3 4 5
Wektor liczb całkowitych można stworzyć jako ciąg liczbowy (sekwencję) o interwale 1 (ciąg rosnący) lub -1 (ciąg malejący) używając dwukropka (:
), gdzie określony jest początek i koniec zakresu (start:koniec
).
= 1:5 # sekwencja
vec vec
[1] 1 2 3 4 5
# stworzenie wektora tekstowego
= c("a", "b", "c", "d", "e")
vec vec
[1] "a" "b" "c" "d" "e"
Aby odwołać się do poszczególnych elementów wektora używa się pojedynczych nawiasów kwadratowych ([]
) oraz indeksów.
# selekcja poprzez indeks
3] vec[
[1] "c"
1:3] vec[
[1] "a" "b" "c"
-5] vec[
[1] "a" "b" "c" "d"
Czynnik
Czynnik (factor) używany jest do reprezentowania zmiennych kategorycznych podczas pracy z danymi jakościowymi, takimi jak etykiety czy klasy, ponieważ przechowują unikalne wartości kategorii. Mogą być również uporządkowane (stopniowane) według określonej kolejności (np. niski < średni < wysoki).
Czynniki są przechowywane jako liczby całkowite, tj. każdej kategorii przypisywany jest unikalny kod liczby całkowitej, co efektywnie ogranicza ilość zajmowanej pamięci. Dodatkowo, przechowywane są etykiety (opisy) powiązane z tymi liczbami całkowitymi.
Do tworzenia czynników służy funkcja factor()
.
= factor(c("Drzewo", "Skała", "Budynek", "Drzewo", "Drzewo"))
fct
length(fct) # liczba wszystkich elementów w wektorze
[1] 5
nlevels(fct) # liczba kategorii
[1] 3
levels(fct) # wyświetl kategorie
[1] "Budynek" "Drzewo" "Skała"
Macierz
Macierze (matrix) to dwuwymiarowe tablice składające się z wierszy oaz kolumn, w których wszystkie elementy są tego samego typu.
Do tworzenia macierzy służy funkcja matrix()
.
= matrix(1:9, ncol = 3)
mat mat
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
Podobnie jak w przypadku wektorów, selekcja danych odbywa się poprzez nawiasy kwadratowe i wskazanie dwóch indeksów w tej kolejności: [wiersze, kolumny]
.
# selekcja pierwszego wiersza
1, ] mat[
[1] 1 4 7
# selekcja pierwszej kolumny
1] mat[,
[1] 1 2 3
Lista
Lista jest uniwersalną strukturą danych, która może przechowywać dowolne zbiory obiektów o różnych typach i długościach. Listy mogą zawierać inne listy (a nawet inne struktury), tworząc zagnieżdżone hierarchie o dowolnej głębokości.
Do tworzenia list służy funkcja list()
.
= list(imie = "Ania", wiek = 25, oceny = c(4, 4, 5), czy_student = TRUE)
lst lst
$imie
[1] "Ania"
$wiek
[1] 25
$oceny
[1] 4 4 5
$czy_student
[1] TRUE
Selekcja w przypadku list jest bardziej zaawansowana niż w przypadku wektorów, ponieważ można dokonać jej na trzy różne sposoby:
- znak dolara
$
jeśli lista posiada nazwy, - podwójne nawiasy kwadratowe
[[]]
(zwraca tylko zawartość listy), - pojedynczy nawias kwadratowy
[]
(zwraca listę i jej zawartość).
$imie lst
[1] "Ania"
"oceny"] # zwrócona jest lista lst[
$oceny
[1] 4 4 5
"oceny"]] # zwrócony jest wektor lst[[
[1] 4 4 5
Jeśli mamy do czynienia ze strukturą zagnieżdżoną, to do selekcji używamy kolejne nawiasy kwadratowe lub symbol dolara, które odnoszą się do kolejnych poziomów w hierarchii.
= list(
lst osoba1 = list(imie = "Ania", wiek = 25),
osoba2 = list(imie = "Andrzej", wiek = 30)
)
$osoba1$wiek # wiek pierwszej osoby lst
[1] 25
Ramka danych
Ramka danych (data frame) jest fundamentalną i najczęściej używaną strukturą danych do przechowywania i przetwarzania danych tabelarycznych (tj. zorganizowane w wierszach i kolumnach, jak w arkuszu kalkulacyjnym czy bazie danych). Znajomość ramek danych jest absolutnie niezbędna do przeprowadzania wszelkiego rodzaju analiz danych!
Ramka danych ma dwuwymiarowy, prostokątny format, składający się z wierszy i kolumn. Każdy wiersz reprezentuje pojedynczą obserwację (rekord). Każda kolumna reprezentuje zmienną (atrybut), które mogą być różnego typu. Co więcej, kolumny muszą posiadać nazwy oraz dokładnie tę samą długość. W sytuacji, gdy kolumny nie mają tej samej długości, używa się brakujących wartości NA
(Not Available).
Ramkę danych można stworzyć używając funkcję data.frame()
i definiując wektory jako kolumny.
= data.frame(
df 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
Selekcja danych wygląda identycznie jak w przypadku list (ponieważ formalnie ramka danych jest listą).
$imie df
[1] "Ania" "Andrzej"
$imie[1] df
[1] "Ania"
1, 1] df[
[1] "Ania"
$wiek == 25, "imie"] df[df
[1] "Ania"
Operatory
Arytmetyczne
- Dodawanie
+
, - Odejmowanie
-
, - Mnożenie
*
, - Dzielenie
/
, - Modulo
%%
(reszta z dzielenia), - Potęgowanie
^
.
= 10
a = 3 b
+ b a
[1] 13
- b a
[1] 7
* b a
[1] 30
/ b a
[1] 3.333333
%% b a
[1] 1
^ b a
[1] 1000
Porównawcze
- Operator równości
==
, - Operator negacji równości
!=
, - Operatory nierówności
>
,>=
,<
,<=
.
= 10
a = 3 b
== b a
[1] FALSE
!= b a
[1] TRUE
< b a
[1] FALSE
> b a
[1] TRUE
Operatory porównawcze są bardzo przydatne do indeksowania elementów.
= c(1, 2, 3, 4, 5)
vec vec
[1] 1 2 3 4 5
# zwraca wartość logiczną dla każdego elementu
>= 3 vec
[1] FALSE FALSE TRUE TRUE TRUE
# zwraca tylko te elementy, które spełniają warunek
>= 3] vec[vec
[1] 3 4 5
Logiczne
- Koniunkcja
&
(TRUE
, jeśli obie wartości są prawdziwe), - Alternatywa
|
(TRUE
, jeśli przynajmniej jedna wartość jest prawdziwa), - Negacja
!
(odwraca wartość logiczną).
= 10
a > 0 & a < 100 a
[1] TRUE
TRUE & FALSE
[1] FALSE
TRUE | FALSE
[1] TRUE
Operatory logiczne mogą być pojedyncze (&
, |
) lub podwójne (&&
, ||
). Pojedyncze działają element po elemencie wektorów, podczas gdy podwójne działają dla wektorów składających się wyłącznie z jednego elementu (tzw. skalarów). Dodatkowo, jeśli pierwszy warunek jest wystarczający do określenia wyniku, to nie jest wykonywana ewaluacja kolejnych warunków.
# zwraca dwie wartości logiczne
c(TRUE, FALSE) & c(TRUE, TRUE)
[1] TRUE FALSE
Operatory pojedyncze stosuje się najczęściej do przetwarzania danych (np. filtrowania ramek danych), natomiast operatory podwójne wykorzystuje się w przypadku instrukcji warunkowych, gdzie wymagana jest jednoznaczna wartość logiczna.
Zadania
Oblicz powierzchnię koła o promieniu 10 cm ze wzoru \(\pi r^2\). Jako liczby \(\pi\) użyj stałej
pi
.Stwórz wektor liczb od 1 do 6. Jeśli liczba jest parzysta, to zamień jej wartość na 0 używając operacji modulo.
Obiekt
letters
zawiera litery alfabetu. Wybierz z niego 5 pierwszych liter.Stwórz ramkę danych składającą się z następujących kolumn:
ID
: 1, 2, 3, 4, 5miasto
: Warszawa, Poznań, Kraków, Toruń, Wrocławtemperatura
: 22, 18, 17, 22, 18
Następnie wyświetl tylko te nazwy miast, w których odnotowano temperaturę powyżej 20 stopni Celsjusza.