R is the lingua franca of statistical research. Work in all other languages should be discouraged.
– Jan de Leeuw (as quoted by Matt Pocernich on R-help)
JSM 2003, San Francisco (August 2003)fortune(78)
R to sam język programowania i środowisko do obliczeń statystycznych.
Język R powstał na początku lat 90. XX wieku w Nowej Zelandii, na Uniwersytecie w Auckland. Jego twórcami byli Ross Ihaka i Robert Gentleman - stąd nazwa “R” pochodzi od pierwszych liter ich imion.
R został stworzony jako darmowa implementacja komercyjnego języka S, który powstał w Bell Laboratories w latach 70. Ihaka i Gentleman chcieli stworzyć narzędzie do nauczania statystyki, które byłoby dostępne dla studentów bez kosztów licencji.
R został po raz pierwszy udostępniony publicznie w 1993 roku. W 1995 roku Martin Mächler z ETH Zurich przekonał twórców do udostępnienia R na licencji GNU GPL, co uczyniło go prawdziwie open source’owym projektem.
W 1997 roku utworzono R Core Team - grupę deweloperów odpowiedzialnych za rozwój języka. To właśnie ta grupa kontroluje kod źródłowy R do dzisiaj (https://cran.r-project.org/).
Wersja 1.0.0: Pierwsza stabilna wersja R 1.0.0 została wydana 29 lutego 2000 roku - symboliczna data w “przestępnym” roku.
RStudio to znacznie późniejszy projekt - to zintegrowane środowisko programistyczne (IDE), które ułatwia pracę z językiem R. RStudio powstało dopiero w 2011 roku, założone przez JJ Allaire.
RStudio to:
Wygodny edytor kodu z podświetlaniem składni
Panel z wizualizacją danych i wykresów
Zarządzanie projektami
Integrację z systemami kontroli wersji (Git)
Podgląd zmiennych i obiektów w pamięci
i inne
W 2022 roku firma RStudio zmieniła nazwę na Posit, by lepiej odzwierciedlić fakt, że rozwija narzędzia nie tylko dla R, ale też dla Pythona i innych języków. Samo oprogramowanie RStudio Desktop nadal nosi tę nazwę.
Więc krótko: R ma ~30 lat, RStudio ~13 lat - to narzędzie powstałe dla już istniejącego języka.
Krótko omówimy teraz na zajęciach, dla nieskupionych (nieobecnych) materiał wideo (po polsku):
lub
Sprawdźmy wersję R, którą mamy aktualnie zainstalowaną na naszym komputerze.
version
## _
## platform x86_64-w64-mingw32
## arch x86_64
## os mingw32
## crt ucrt
## system x86_64, mingw32
## status
## major 4
## minor 4.3
## year 2025
## month 02
## day 28
## svn rev 87843
## language R
## version.string R version 4.4.3 (2025-02-28 ucrt)
## nickname Trophy Case
Polecenie version
w R
dostarcza szczegółowych informacji o wersji R, którą aktualnie używamy,
określa platformę sprzętową i system operacyjny, podaje informacje o
dacie i czasie kompilacji R, wersji kompilatora, etc. Wszystko to może
być ważne z punktu widzenia pracy kolektywnej na jednym projekcie
(wersja R i jego bibliotek).
Uwaga co do instalowania nowych wersji
R
. Ogólnie warto. Mniej więcej co roku, w
kwietniu, wypuszczana jest duża aktualizacja. W ciągu roku również
pojawiają się pomniejsze aktualizacje. Samo zainstalowanie nowej wersji
R
nie powinno psuć nam kodu, który działał
w wersjach wcześniejszych (konserwatywni deweloperzy). Powinna za to
poprawić się wydajność.
Jednym z mankamentów R
w porównaniu do
innych języków jest jego powolność. Jest jednak piekielnie wygodny przy
konceptualizacji i pisaniu kodu. Powszechny dowcip mówi, że “gdy
programista R ‘kompiluje’ swój kod, programista C szuka na
StackOverflow (teraz pyta ChatGPT) jak wczytać plik
csv”.
options(repos = c(CRAN = "https://cloud.r-project.org")) # <- funkcja available.packages() wymaga określenia lustra CRAN (Comprehensive R Archive Network), z którego mają być pobierane informacje o dostępnych pakietach.
paste0("Aktualna liczba pakietów na dzień kompilacji poniższego dokumentu (", Sys.Date(), ") html to: ",
nrow(available.packages())
)
## [1] "Aktualna liczba pakietów na dzień kompilacji poniższego dokumentu (2025-10-16) html to: 22827"
Jeśli w przyszłości sami będziemy tworzyć pakiety poniżej
przydatny pakiet do sprawdzania:
czy ta nazwa jest już zajęta na CRAN, Bioconductor, GitHub etc.,
czy nazwa nie jest zastrzeżonym znakiem towarowym,
czy nie ma niepożądanych skojarzeń językowych (np. wulgaryzmy), etc.
install.packages("avaliable")
library(available)
available("Moja_nazwa_pakietu")
Na stronie projektu można sprawdzać pakiety “manualnie”:
https://cran.r-project.org/web/packages/available_packages_by_date.html
Co może jednakowoż psuć nam kod, to aktualizacja paczek, których używamy. Pracując na projektach, zazwyczaj “mrozi się” wersje paczek i pilnuje poszczególnych użytkowników, żeby pracowali na spójnych co do wersji paczkach (czytaj: odbiera im się możliwość samodzielnych aktualizacji).
Pakietem R
, który służy do zarządzania
wersjami pakietów jest np. packrat
. Packrat
umożliwia izolowanie projektów R
od
zewnętrznych zależności, tak aby w przypadku aktualizacji pakietów,
projekt pozostał stabilny. Packrat
zapewnia również
narzędzia do zarządzania bibliotekami i łatwe przełączanie między
różnymi wersjami pakietów. Ale to póki co tytułem dygresji i żeby było w
notatkach.
Aby zainstalować nowy pakiet można ściągnąć odpowiedni plik ze strony https://cran.r-project.org/web/packages/ i zainstalować go ręcznie
Wygodniej jest wykonać polecenie:
install.packages("nazwa_pakietu")
Aby załadować zainstalowany pakiet do pamięci w danej sesji R
należy wykonać polecenie:
library(nazwa_pakietu
) albo
require(nazwa_pakietu)
Aktualizację wszystkich zainstalowanych pakietów można wykonać za
pomocą polecenia: update.packages()
Aktualizacje bywają niezwykle pożyteczne, i zdradliwe zarazem. Z jednej
strony niosą nowe, rozszerzone, możliwości, przyspieszenie,
optymalizację (niepotrzebne skreślić), z drugiej mogą wywalić cały
projekt do kosza (zmiana argumentów funkcji, użycie innych metod,
wygaszenie jakiejś funkcjonalności). Pakiety mają swoje cykle
życia.
Zainstalujmy sobie pierwszy pakiet poleceniem
install.packages("fortunes")
. Uruchommy pakiet poleceniem
library(fortunes)
, a następnie skorzystajmy z dostępnej tam
funkcji fortune()
(bez żadnego argumentu).
# install.packages("fortunes") # mam już ten pakiet, stąd zakomentowanie linijki
library(fortunes)
fortune()
##
## You can't expect statistical procedures to rescue you from poor data.
## -- Berton Gunter (on dealing with missing values in a cluster analysis)
## R-help (April 2005)
Możemy użyć silnika wyszukiwarki wbudowanej w RStudio. Default’owo prawe dolne okienko, przycisk Help (albo Pomoc w przypadku polskojęzycznej instalacji soft’u)
Poleceniami w konsoli help()
lub z
użyciem znaku zapytania przed szukaną frazą, pojedynczy
?
(równoważny poleceniu
help(package = "nazwa_pakietu")
)
bądź
podwójny ??
(równoważny poleceniu
help.search("nazwa_pakietu")
).
help() # wywołanie dokumentacji - pomoc na temat funkcji help
help.start() # Uruchamia przeglądarkę internetową z interfejsem do dokumentacji R. Oferuje dostęp do pełnej dokumentacji, w tym podręczników, zainstalowanych pakietów i innych zasobów.
help(abs) # wywołanie pomocy na temat konkretnej funkcji
?abs # jak wyżej - równoznaczne
??abs
help.search("abs") # wyszukuje w dokumentacji funkcje związane z danym hasłem, starszy odpowiednik ??
apropos("abs") # funkcja apropos() w R jest używana do wyszukiwania obiektów w środowisku R, które zawierają określony ciąg znaków w swojej nazwie. Jest to bardzo przydatne narzędzie, gdy chcesz znaleźć funkcje, zmienne lub inne obiekty, ale nie pamiętasz ich dokładnych nazw.
W RStudio można ustawić kursor na nazwie funkcji i nacisnąć F1
Zewnętrzne źródła np. https://rseek.org/ bądź każdy inny silnik
Napiszmy sobie jeszcze nieśmiertelną w każdym języku programowania linijkę kodu…
print("Hello World!")
## [1] "Hello World!"
Znacznik > w konsoli R oznacza, że R czeka na nasze polecenia.
+ w konsoli oznacza niedokończone polecenie.
# służy do komentowania
Chcąc uruchomić komendę/ linię kodu można postawić kursor w dowolnym miejscu wiersza z kodem, ewentualnie zaznaczyć interesujący nas fragment, który zamierzamy uruchomić, a następnie albo korzystamy ze skrótu klawiszowego Ctrl + Enter, albo myszką klikamy przycisk RUN
Pracę warto rozpocząć dwoma poleceniami getwd() oraz setwd(“…”)
Wielkość liter ma znaczenie – „A” i „a” oznaczają co innego, R jest case sensitive
Poszczególne komendy mogą być rozdzielane albo ENTER’em albo ; (jak w C++)
2 + 6; 5 * 6; 3 - 6
## [1] 8
## [1] 30
## [1] -3
# równoważne z
2 + 6
## [1] 8
5 * 6
## [1] 30
3 - 6
## [1] -3
Spacje nie mają znaczenia (chyba, że sklejają się dwie funkcje czy wyrażenia)
Komentarze można wprowadzać po znaku # Nie będą interpretowane od znaku do końca wiersza. Użyteczny skrót: Ctrl + Shift + C
W przypadku niekompletnej komendy konsola R informuje znakiem +
5 + 6 - 3 - 6 + 4 + 2 -
4 + 8 + 3 + 2 + 7
## [1] 24
Arytmetyczne:
dodawanie +
,
odejmowanie -
,
mnożenie *
,
dzielenie /
,
potęgowanie ^
albo **
Porównawcze: >
, >=
,
<
, <=
, ==
,
!=
Logiczne:
negacja !
,
koniunkcja &
,
alternatywa |
(dodatkowo również
&&
oraz ||
)
Formuła modelu: ~
# Dodawanie
5 + 7
## [1] 12
# Odejmowanie
8 - 5
## [1] 3
# Mnożenie
4 * 6
## [1] 24
# Dzielenie
(5 + 5) / 2
## [1] 5
# Potęgowanie
2^3 # lub
## [1] 8
2**3
## [1] 8
# Pierwiastkowanie
36^(1/2) # lub przez funkcję sqrt(36) wbudowaną w R
## [1] 6
36^1/2 # pilnować nawiasów
## [1] 18
36^0.5
## [1] 6
# Część całkowita z dzielenia
31%/%6
## [1] 5
# Modulo
31%%6
## [1] 1
# działania rozbudowane
2^3+4*(16-10)
## [1] 32
3 ^ 2 - 1 + 3 ** (2 - 1) # ze spacjami być może czytelniej, nie wpływają na ewaluację wyrażenia
## [1] 11
5 + 6 - 3 - 6 + 4 + 2 -
4 + 8 + 3 + 2 + 7 # jak odpalić takie 'złamane' na dwie linijki działanie?
## [1] 24
# skalary, wartości 'atomowe'
x <- 666
print(x)
## [1] 666
rm(x) # żeby usunąć ze środowiska i udowodnić, że zadziała
666 -> x
print(x)
## [1] 666
x = 666
print(x)
## [1] 666
# jeśli tworzony obiekt już istnieje jego wartość będzie zastąpiona nową
x = 69
print(x)
## [1] 69
# jeśli polecenie będące przypisaniem umieścimy w nawiasie () to po jego wykonaniu wynikowy obiekt będzie także wyświetlony w konsoli
(x = 69)
## [1] 69
# możemy sprawdzić, czy istnieje obiekt o nazwie x w przestrzeni funkcją exists(), gdzie nazwę obiektu podaje się jako argument tekstowy (ujęty w cudzysłów)
# exists(x)
exists("x")
## [1] TRUE
To samo co robiliśmy przed momentem na liczbach działa również na zmiennych.
x <- 3
y <- 4
z <- x+y
print(z)
## [1] 7
x*y
## [1] 12
x%%y
## [1] 3
Konwencje nazewnictwa zmiennych:
moja_zmienna <- 666
mojaZmienna <- 333
moja.zmienna <- 999
MojaKlasa <- setClass("Kognitywistyka")
W języku R wyróżniamy kilka podstawowych typów danych, które są
kluczowe do pracy z danymi. Oto one:
Character
: Typ danych przechowujący tekst. Każdy
element jest traktowany jako ciąg znaków. Przykład:
"Hello, World!"
.
Numeric
: Typ danych przechowujący liczby
zmiennoprzecinkowe. Przykład: 3.14
.
Integer
: Typ danych przechowujący liczby całkowite.
W R liczby całkowite są oznaczane literą L
po liczbie.
Przykład: 42L
.
Logical
: Typ danych przechowujący wartości logiczne
TRUE
(bądź T
) lub FALSE
(tudzież
F
). Przykład: TRUE
.
Complex
: Typ danych przechowujący liczby zespolone.
Przykład: 1 + 2i
.
Factor
: Specjalny typ danych używany do
przechowywania zmiennych kategorycznych. Przykład:
factor(c("male", "female", "female", "male"))
.
Date
: Typ danych przechowujący daty. Przykład:
as.Date("2024-09-05")
.
POSIXct
: Typ danych przechowujący daty i czasy.
Przykład: as.POSIXct("2024-09-05 09:25:01")
.
Każdy z tych typów danych ma swoje specyficzne zastosowania i jest używany w różnych kontekstach analizy danych. Warto znać te podstawowe typy, aby efektywnie pracować w
Typ (klasę) obiektu w R można sprawdzić za pomocą funkcji class().
moja_dokladna_liczba <- 54.7 # numeric
class(moja_dokladna_liczba)
## [1] "numeric"
moja_liczba <- 53 # teoretycznie integer
class(moja_liczba)
## [1] "numeric"
moja_liczba <- 53L
class(moja_liczba) # mamy to
## [1] "integer"
# Wniosek, jeśli chcemy, aby wektor numeryczny przechowywał wartości całkowite (integer), należy podawać wartości liczbowe z dopisaną literą L
moje_slowo <- "histogram" # character (string), dygresja: możliwe też pojedyncze nawiasy '...'
class(moje_slowo)
## [1] "character"
moja_wart_logiczna <- T # Boolean data type (logical)
class(moja_wart_logiczna)
## [1] "logical"
class(moja_wart_logiczna) == "logical" # do sprawdzenia np. w jakiejś pętli, czy jakaś transformacja nie spowodowała zmiany typu na niechciany
## [1] TRUE
moja_wart_logiczna2 <- TRUE
str(moja_wart_logiczna2)
## logi TRUE
# output funkcji będzie wyglądał nieco inaczej na różnych typach obiektów
Jeśli nie podobają nam się typy danych
zastosowane przez R’a, możemy próbować je zmienić.
# czasem przydaje się trzymać wartość numeryczną jako string
moja_dokladna_liczba <- as.character(moja_dokladna_liczba)
class(moja_dokladna_liczba)
## [1] "character"
moja_dokladna_liczba
## [1] "54.7"
# wybuchnie?
moje_slowo <- as.numeric(moje_slowo)
## Warning: NAs introduced by coercion
class(moje_slowo)
## [1] "numeric"
moje_slowo # buuuuu
## [1] NA
# wtf?
moja_wart_logiczna2 <- as.integer(moja_wart_logiczna2)
class(moja_wart_logiczna2)
## [1] "integer"
# ale...
moja_wart_logiczna2
## [1] 1
1 + as.logical(moja_wart_logiczna2) # serio?
## [1] 2
as.integer(c(5.1, 3.2, 7.9, 1.4)) # a tu?
## [1] 5 3 7 1
# W przypadku użycia funkcji `as.integer` na liczbach, które nie są liczbami całkowitymi, R zaokrągla je w dół
Ogólnie hierarchia typów wygląda następująco: character
> numeric
> integer
>
logical
Wektor jest podstawową strukturą danych w języku R. Jest to uporządkowany zbiór elementów tego samego typu.
Ważne: W R nawet pojedyncza wartość jest wektorem o długości 1!
# To jest skalar, ale też wektor długości 1
x <- 5
x
## [1] 5
length(x)
## [1] 1
Zdefiniujmy zmienne używając wszechobecnej w R funkcji c(). c prawdopodobnie od combine
# Wektor numeryczny
(oceny_stat_R <- c(4,5,2,2,3))
## [1] 4 5 2 2 3
# Wektor znakowy
(za_co <- c("klasowka", "aktywnosc", "sprawdzian", "sprawdzian", "projekt"))
## [1] "klasowka" "aktywnosc" "sprawdzian" "sprawdzian" "projekt"
# Wektor logiczny
(warunki <- c(TRUE, FALSE, TRUE, TRUE))
## [1] TRUE FALSE TRUE TRUE
Nazywanie wektora
# nadanie wartościom wektora nazw
names(oceny_stat_R) <- za_co
# Obejrzyjmy
print(oceny_stat_R)
## klasowka aktywnosc sprawdzian sprawdzian projekt
## 4 5 2 2 3
# funkcja c() umożliwia nadanie nazw kolejnym elementom w konwencji nazwa = wartość
id <- c(pierwszy = 1, drugi = 2, trzeci = 3)
Swoją drogą, czy da się nakreślić jakiś “sznyt charakterologiczny” osoby z takimi ocenami?
Strukturę obiektu można sprawdzić funkcją
str()
str(oceny_stat_R)
## Named num [1:5] 4 5 2 2 3
## - attr(*, "names")= chr [1:5] "klasowka" "aktywnosc" "sprawdzian" "sprawdzian" ...
Podstawowe operacje na wektorach
wektor_1 <- c(2,4,7,3)
wektor_2 <- c(3,8,9,2)
# dodawanie wektorów
print(suma_wektorow <- wektor_1 + wektor_2)
## [1] 5 12 16 5
# łączenie wektorów
(concat_wektorow <- c(wektor_1, wektor_2))
## [1] 2 4 7 3 3 8 9 2
To może coś wbudowaną funkcją by zrobić…
# gdybyśmy nie znali żadnej funkcji arytmetycznej w R musielibyśmy liczyć "na piechotę"
(4+5+2+2+3)/5
## [1] 3.2
# tak można
sum(suma_wektorow)
## [1] 38
length(oceny_stat_R)
## [1] 5
sum(concat_wektorow)
## [1] 38
mean(oceny_stat_R) # Średnia ocen z przedmiotu
## [1] 3.2
# albo...
sum(oceny_stat_R)/length(oceny_stat_R)
## [1] 3.2
Obejrzyjmy wektory składające się wyłącznie w elementów
logicznych i zaaplikujmy do nich poznane operatory
x <- c(T, F, F)
y <- c(T, F, T)
x|y # W R operator alternatywy <OR (lub)> dla wektorów logicznych to operator |
## [1] TRUE FALSE TRUE
!x # negacja
## [1] FALSE TRUE TRUE
x&y # W R operator koniunkcji (AND) dla wektorów logicznych to operator &.
## [1] TRUE FALSE FALSE
Sekwencje
(id <- 1:3)
## [1] 1 2 3
(id <- c(1:3))
## [1] 1 2 3
10:1
## [1] 10 9 8 7 6 5 4 3 2 1
-5:5
## [1] -5 -4 -3 -2 -1 0 1 2 3 4 5
5:-5
## [1] 5 4 3 2 1 0 -1 -2 -3 -4 -5
5.1:8.2 # ostatnia wartość nie jest wartością wskazaną jako kończąca sekwencję
## [1] 5.1 6.1 7.1 8.1
seq(from=, to=, by=, length.out =…)
seq(1, 10, 1) # równoważnik 1:10
## [1] 1 2 3 4 5 6 7 8 9 10
seq(1, 10, 2) # 9?
## [1] 1 3 5 7 9
(seq(1,10))
## [1] 1 2 3 4 5 6 7 8 9 10
class(seq(1,10)) # <- wydaje się oczywiste
## [1] "integer"
(seq(1,10,1))
## [1] 1 2 3 4 5 6 7 8 9 10
class(seq(1,10,1)) # <- wydaje się mnie oczywiste, dodaliśmy jedynie jawnie 3. argument w funkcji
## [1] "numeric"
(seq(1L,10L,1))
## [1] 1 2 3 4 5 6 7 8 9 10
class(seq(1L,10L,1L)) # <- patent, żeby znów zachowywało się "intuicyjnie"
## [1] "integer"
# lub
(seq(1,10,1))
## [1] 1 2 3 4 5 6 7 8 9 10
class(seq(1,10,1L))
## [1] "numeric"
(sekwencjaNumericow <- seq(from = 1,
to = 10,
length.out = 20))
## [1] 1.000000 1.473684 1.947368 2.421053 2.894737 3.368421 3.842105
## [8] 4.315789 4.789474 5.263158 5.736842 6.210526 6.684211 7.157895
## [15] 7.631579 8.105263 8.578947 9.052632 9.526316 10.000000
(sekwencjaNumericow2 <- seq.int(from = 1,
to = 10,
length.out = 19)) # == seq(1, 10, by = 0.5), gdyż "przepis" na by to:
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0
## [16] 8.5 9.0 9.5 10.0
# by = (to - from)/(length.out - 1) -> ?seq
(sekwencjaNumericow3 <- seq(from = 0.5, # <-
to = 10,
length.out = 20))
## [1] 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5
## [16] 8.0 8.5 9.0 9.5 10.0
Powtarzanie wartości
rep(666, times = 10)
## [1] 666 666 666 666 666 666 666 666 666 666
rep(1:5, times = 10)
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3
## [39] 4 5 1 2 3 4 5 1 2 3 4 5
rep(1:5, each = 10)
## [1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4
## [39] 4 4 5 5 5 5 5 5 5 5 5 5
(szpital<-c(rep("lekarz",6),
rep("administracja",7),
rep("pielęgniarka",9))
) # rep() na wektorach
## [1] "lekarz" "lekarz" "lekarz" "lekarz"
## [5] "lekarz" "lekarz" "administracja" "administracja"
## [9] "administracja" "administracja" "administracja" "administracja"
## [13] "administracja" "pielęgniarka" "pielęgniarka" "pielęgniarka"
## [17] "pielęgniarka" "pielęgniarka" "pielęgniarka" "pielęgniarka"
## [21] "pielęgniarka" "pielęgniarka"
trufolsy <- (rep(c(TRUE, FALSE), times = 5)) # rep() na trufolsach
Indeksowanie wektora
UWAGA: R indeksuje od 1, nie od 0!
# stwórzmy sobie znakowy wektor
owoce <- c("jabłko", "banan", "gruszka", "pomarańcza", "winogrono")
# Pierwszy element
owoce[1]
## [1] "jabłko"
# Trzeci element
owoce[3]
## [1] "gruszka"
# Wiele elementów
owoce[c(1, 3, 5)]
## [1] "jabłko" "gruszka" "winogrono"
# Zakres
owoce[2:4]
## [1] "banan" "gruszka" "pomarańcza"
# Wszystko oprócz pierwszego
owoce[-1]
## [1] "banan" "gruszka" "pomarańcza" "winogrono"
# Wszystko oprócz pierwszego i ostatniego
owoce[-c(1, 5)]
## [1] "banan" "gruszka" "pomarańcza"
Indeksowanie logiczne
liczby <- c(5, 12, 8, 3, 15, 20, 7)
# Które liczby są większe od 10?
liczby > 10
## [1] FALSE TRUE FALSE FALSE TRUE TRUE FALSE
# Wybierz liczby większe od 10
liczby[liczby > 10]
## [1] 12 15 20
# Liczby parzyste
liczby[liczby %% 2 == 0]
## [1] 12 8 20
# Liczby między 5 a 15
liczby[liczby >= 5 & liczby <= 15]
## [1] 5 12 8 15 7
Indeksowanie przez nazwy
# Nadajemy nazwy elementom
wiek <- c(25, 30, 22, 28)
names(wiek) <- c("Anna", "Jan", "Kasia", "Piotr")
wiek
## Anna Jan Kasia Piotr
## 25 30 22 28
# Dostęp przez nazwę
wiek["Jan"]
## Jan
## 30
# Wiele nazw
wiek[c("Anna", "Kasia")]
## Anna Kasia
## 25 22
# A co w sytuacji?
names(wiek) <- c("Anna", "Jan", "Kasia", "Anna") # 2x "Anna"
wiek["Anna"] # :(
## Anna
## 25
wiek[c("Anna", "Anna")] # :(
## Anna Anna
## 25 25
# wówczas:
wiek[names(wiek) == "Anna"]
## Anna Anna
## 25 28
Ważne: Gdy wektory mają różne długości, R “recykluje” krótszy wektor:
c(1, 2, 3, 4) + c(10, 20) # c(10, 20) jest użyte dwa razy
## [1] 11 22 13 24
UWAGA: Gdy długość nie jest wielokrotnością, dostaniemy ostrzeżenie
c(1, 2, 3) + c(10, 20)
## Warning in c(1, 2, 3) + c(10, 20): longer object length is not a multiple of
## shorter object length
## [1] 11 22 13
zmiana elementów wektora
wektor <- seq(10,50, by = 10)
# Zmiana pojedynczego elementu
wektor[3] <- 999
wektor
## [1] 10 20 999 40 50
# Zmiana wielu elementów
wektor[c(1, 5)] <- c(111, 555)
wektor
## [1] 111 20 999 40 555
# Dodawanie elementów na końcu
wektor <- c(wektor, 60, 70)
wektor
## [1] 111 20 999 40 555 60 70
# Usuwanie elementów
wektor <- wektor[-c(2, 4)]
wektor
## [1] 111 999 555 60 70
NA
- Not Available (brakujące dane)
wektor_z_brakami <- c(1, 2, NA, 4, 5)
wektor_z_brakami
## [1] 1 2 NA 4 5
# Większość funkcji zwróci NA, jeśli są braki
mean(wektor_z_brakami)
## [1] NA
# Musimy pominąć NA
mean(wektor_z_brakami, na.rm = TRUE)
## [1] 3
# Sprawdzanie NA
is.na(wektor_z_brakami)
## [1] FALSE FALSE TRUE FALSE FALSE
# Ile jest NA?
sum(is.na(wektor_z_brakami))
## [1] 1
NULL
- Brak
# NULL - pusty obiekt
x <- NULL
length(x)
## [1] 0
NaN
- Not a Number (nie-liczba)
# NaN - Not a Number (nieokreślona operacja matematyczna)
0/0
## [1] NaN
Inf
- Infinity (nieskończoność)
1/0 # Inf (nieskończoność)
## [1] Inf
-1/0 # -Inf (-nieskończoność)
## [1] -Inf
Sortowanie
liczby <- c(23, 5, 17, 8, 42, 11)
# Sortowanie rosnąco
sort(liczby)
## [1] 5 8 11 17 23 42
# Sortowanie malejąco
sort(liczby, decreasing = TRUE)
## [1] 42 23 17 11 8 5
# Indeksy posortowanych elementów
order(liczby)
## [1] 2 4 6 3 1 5
# Użycie order() do sortowania
liczby[order(liczby)]
## [1] 5 8 11 17 23 42
Inne przydatne funkcje
wektor <- c(3, 7, 2, 7, 9, 2, 5, 7)
# Unikalne wartości
unique(wektor)
## [1] 3 7 2 9 5
# Ile razy występuje każda wartość
table(wektor)
## wektor
## 2 3 5 7 9
## 2 1 1 3 1
# Czy element występuje w wektorze
7 %in% wektor
## [1] TRUE
100 %in% wektor
## [1] FALSE
# Pozycja elementu
which(wektor == 7)
## [1] 2 4 8
# Liczba elementów spełniających warunek
sum(wektor > 5)
## [1] 4
# Odwracanie kolejności
rev(wektor)
## [1] 7 5 2 9 7 2 7 3
Filtrowanie danych
# Wyniki egzaminów studentów
wyniki <- c(45, 78, 92, 67, 83, 54, 88, 71, 96, 62)
imiona_studentow <- c("Anna", "Bartek", "Celina", "Darek", "Ewa",
"Filip", "Gosia", "Heniek", "Iza", "Janek")
# Kto zdał (>= 60 punktów)?
zdali <- wyniki >= 60
imiona_studentow[zdali]
## [1] "Bartek" "Celina" "Darek" "Ewa" "Gosia" "Heniek" "Iza" "Janek"
# Kto ma najlepszy wynik?
max(wyniki)
## [1] 96
imiona_studentow[which.max(wyniki)]
## [1] "Iza"
Normalizacja danych
# Dane surowe
dane <- c(10, 15, 8, 20, 12)
# Normalizacja do zakresu [0, 1]
dane_norm <- (dane - min(dane)) / (max(dane) - min(dane))
dane_norm
## [1] 0.1666667 0.5833333 0.0000000 1.0000000 0.3333333
Standaryzacja danych
# Standaryzacja (średnia = 0, sd = 1)
dane_std <- (dane - mean(dane)) / sd(dane)
dane_std
## [1] -0.6396021 0.4264014 -1.0660036 1.4924050 -0.2132007
round(mean(dane_std), 10) # Sprawdzenie (w przybliżeniu 0)
## [1] 0
Modyfikacja wektorów - budowanie wektora z innego wektora
id <- c(pierwszy = 1, drugi = 2, trzeci = 3)
# a budować wektor możemy z "części znalezionych na szrocie"
szesc = 6
id2 <- c(czwarty = id[2]*2, piąty = id[3]+2, szósty = szesc)
Symulacja
# Rzut kostką 1000 razy
set.seed(123) # Dla powtarzalności
rzuty <- sample(1:6, size = 1000, replace = TRUE)
# Rozkład wyników
table(rzuty)
## rzuty
## 1 2 3 4 5 6
## 170 176 171 157 162 164
# Prawdopodobieństwo empiryczne każdej ścianki
table(rzuty) / length(rzuty)
## rzuty
## 1 2 3 4 5 6
## 0.170 0.176 0.171 0.157 0.162 0.164
Wektory “predefiniowane”
# przykłady
letters
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"
LETTERS
## [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
## [20] "T" "U" "V" "W" "X" "Y" "Z"
month.abb
## [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
month.name
## [1] "January" "February" "March" "April" "May" "June"
## [7] "July" "August" "September" "October" "November" "December"
rev(LETTERS) # funkcja odwracająca kolejność wektora
## [1] "Z" "Y" "X" "W" "V" "U" "T" "S" "R" "Q" "P" "O" "N" "M" "L" "K" "J" "I" "H"
## [20] "G" "F" "E" "D" "C" "B" "A"
Co można zrobić na takich wektorach? Na przykład zastosować
funkcję length()
length(letters)
## [1] 26
length(c(month.abb, month.name))
## [1] 24
Konwersja typów.
Przypomnijmy sobie typy danych 3 wektorów w środowisku
class(letters)
## [1] "character"
class(trufolsy)
## [1] "logical"
class(sekwencjaNumericow)
## [1] "numeric"
(wektor = c(letters, trufolsy)); class(wektor)
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
## [10] "j" "k" "l" "m" "n" "o" "p" "q" "r"
## [19] "s" "t" "u" "v" "w" "x" "y" "z" "TRUE"
## [28] "FALSE" "TRUE" "FALSE" "TRUE" "FALSE" "TRUE" "FALSE" "TRUE" "FALSE"
## [1] "character"
(wektor = c(letters, sekwencjaNumericow)); class(wektor) # co wynika ze wspomnianej wcześniej hierarchii typów
## [1] "a" "b" "c" "d"
## [5] "e" "f" "g" "h"
## [9] "i" "j" "k" "l"
## [13] "m" "n" "o" "p"
## [17] "q" "r" "s" "t"
## [21] "u" "v" "w" "x"
## [25] "y" "z" "1" "1.47368421052632"
## [29] "1.94736842105263" "2.42105263157895" "2.89473684210526" "3.36842105263158"
## [33] "3.84210526315789" "4.31578947368421" "4.78947368421053" "5.26315789473684"
## [37] "5.73684210526316" "6.21052631578947" "6.68421052631579" "7.15789473684211"
## [41] "7.63157894736842" "8.10526315789474" "8.57894736842105" "9.05263157894737"
## [45] "9.52631578947368" "10"
## [1] "character"
(wektor = c(trufolsy, sekwencjaNumericow)); class(wektor) # co wynika ze wspomnianej wcześniej hierarchii typów
## [1] 1.000000 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000
## [8] 0.000000 1.000000 0.000000 1.000000 1.473684 1.947368 2.421053
## [15] 2.894737 3.368421 3.842105 4.315789 4.789474 5.263158 5.736842
## [22] 6.210526 6.684211 7.157895 7.631579 8.105263 8.578947 9.052632
## [29] 9.526316 10.000000
## [1] "numeric"
Transpozycja wektora
oceny_stat_R # obejrzyjmy
## klasowka aktywnosc sprawdzian sprawdzian projekt
## 4 5 2 2 3
class(oceny_stat_R)
## [1] "numeric"
is.vector(oceny_stat_R)
## [1] TRUE
t(oceny_stat_R) # transponujmy
## klasowka aktywnosc sprawdzian sprawdzian projekt
## [1,] 4 5 2 2 3
class(t(oceny_stat_R)); is.vector(t(oceny_stat_R))
## [1] "matrix" "array"
## [1] FALSE
# macierz wierszowa (1×5)
t(t(oceny_stat_R)) # transponujmy "do kwadratu", odwrócimy proces? :)
## [,1]
## klasowka 4
## aktywnosc 5
## sprawdzian 2
## sprawdzian 2
## projekt 3
class(t(t(oceny_stat_R))); is.vector(t(t(oceny_stat_R)))
## [1] "matrix" "array"
## [1] FALSE
# macierz wierszowa (5X1)
Do zapamiętania:
NA
wymaga specjalnej obsługi
(na.rm = TRUE
)Najczęstsze pułapki:
NA
Zadania przy tablicy
liczby_1_100 <- 1:100
podzielne_przez_7 <- liczby_1_100[liczby_1_100 %% 7 == 0]
# alternatywnie
podzielne_przez_7_v2 <- seq(from = 7, to = 100, by = 7)
runif()
) z przedziału
od 0 do 100 i znajdź te większe od średniejset.seed(42) # Dla powtarzalności wyników
losowe_liczby <- runif(n = 20, min = 0, max = 100)
srednia <- mean(losowe_liczby)
wieksze_od_sredniej <- losowe_liczby[losowe_liczby > srednia]
imiona <- c("Zofia", "Adam", "Katarzyna", "Bartosz", "Ewa",
"Michał", "Anna", "Piotr", "Dorota", "Krzysztof")
imiona_sorted <- sort(imiona)
imiona_sorted_desc <- sort(imiona, decreasing = TRUE)
imiona <- c("Zofia", "Adam", "Katarzyna", "Bartosz", "Ewa",
"Michał", "Anna", "Piotr", "Dorota", "Krzysztof")
# 1. Obliczanie długości znaków
dlugosci <- nchar(imiona)
# [1] 5 4 9 7 3 6 4 5 6 9
# 2. Uzyskanie kolejności (indeksów) sortującej ROSNĄCO
kolejnosc_rosnaco <- order(dlugosci)
# [1] 5 2 7 1 8 6 9 4 3 10
# 3. Sortowanie wektora imion
imiona_posortowane <- imiona[kolejnosc_rosnaco]
# malejąco
imiona_posortowane_malejaco <- imiona[order(nchar(imiona), decreasing = TRUE)]
sample()
) i oblicz
częstość wypadnięcia orłaset.seed(123) # Dla powtarzalności
# Metoda 1: Używając sample()
# 0 = reszka, 1 = orzeł
rzuty_moneta <- sample(c(0, 1), size = 10000, replace = TRUE)
# Alternatywnie z nazwami:
rzuty_moneta2 <- sample(c("Reszka", "Orzeł"), size = 10000, replace = TRUE)
# Obliczamy częstość orła
liczba_orlow <- sum(rzuty_moneta == 1)
liczba_reszek <- sum(rzuty_moneta == 0)
czestosc_orla <- liczba_orlow / length(rzuty_moneta)
round(czestosc_orla * 100, 2)
## [1] 49.83
round((1 - czestosc_orla) * 100, 2)
## [1] 50.17
table(rzuty_moneta)
## rzuty_moneta
## 0 1
## 5017 4983
prop.table(table(rzuty_moneta2))
## rzuty_moneta2
## Orzeł Reszka
## 0.4959 0.5041
# Prosty wykres słupkowy
# barplot(table(rzuty_moneta),
# names.arg = c("Reszka", "Orzeł"),
# main = "Symulacja 10000 rzutow moneta",
# xlab = "Wynik",
# ylab = "Liczba wystąpień",
# col = c("lightblue", "gold"),
# ylim = c(0, 6000))
# abline(h = 5000, col = "red", lty = 2, lwd = 2)
# text(1.5, 5200, "Oczekiwana wartość (5000)", col = "red")
Funkcja set.seed()
w R służy do ustawienia ziarna
generatora liczb losowych, dzięki czemu wyniki losowań są powtarzalne.
Za każdym razem, gdy używasz funkcji losowych (np.
sample()
, runif()
, rnorm(
) itd.),
R generuje liczby w sposób pseudo-losowy — tzn. opiera się na
algorytmie, który startuje od pewnego ziarna (ang. seed). R
korzysta z tzw. PRNG (Pseudo-Random Number
Generator). Domyślnie jest to algorytm Mersenne Twister. To bardzo
popularny i szybki algorytm generowania liczb pseudo-losowych
(opracowany w 1997 roku przez Matsumoto i Nishimura).
Stwórzmy pierwszą ‘matrycę’
# 3 wiersze zawierającą cyfry od 1 do 9
matrix(1:9, byrow = TRUE, nrow = 3)
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
## [3,] 7 8 9
# oceny semestralne z trzech przedmiotów
stat_R <- c(2,3) # vector()
filozofia <- c(5,5)
matematyka <- c(4,4)
# połączone w wektor
oceny <- c(stat_R, filozofia, matematyka)
# ramka (matryca) z ocenami
oceny_matrix <- matrix(oceny, nrow = 3, byrow = T)
print(oceny_matrix)
## [,1] [,2]
## [1,] 2 3
## [2,] 5 5
## [3,] 4 4
colnames() & rownames()
-> nazywanie ramki
# szykowne nazwy wierszy i kolumn
nazwa_przedmiotu <- c("Statystyka w R", "Filozofia analityczna", "Matematyka Euklidesowa")
semestry <- c("Semestr 1", "Semestr 2")
# przypisanie ich do ramki
colnames(oceny_matrix) <- semestry
rownames(oceny_matrix) <- nazwa_przedmiotu
# Voici
print(oceny_matrix)
## Semestr 1 Semestr 2
## Statystyka w R 2 3
## Filozofia analityczna 5 5
## Matematyka Euklidesowa 4 4
# metoda "od razu"
oceny_matrix <- matrix(oceny,
nrow = 3,
byrow = T,
dimnames = list(nazwa_przedmiotu, semestry)) # jeszcze w sumie nie znamy typu lista
oceny_matrix
## Semestr 1 Semestr 2
## Statystyka w R 2 3
## Filozofia analityczna 5 5
## Matematyka Euklidesowa 4 4
# średnia ocen na koniec roku?
rowMeans(oceny_matrix)
## Statystyka w R Filozofia analityczna Matematyka Euklidesowa
## 2.5 5.0 4.0
Atrybuty macierzy
# klasa utworzonego obiektu
class(oceny_matrix)
## [1] "matrix" "array"
# struktura
str(oceny_matrix)
## num [1:3, 1:2] 2 5 4 3 5 4
## - attr(*, "dimnames")=List of 2
## ..$ : chr [1:3] "Statystyka w R" "Filozofia analityczna" "Matematyka Euklidesowa"
## ..$ : chr [1:2] "Semestr 1" "Semestr 2"
# inne
rownames(oceny_matrix)
## [1] "Statystyka w R" "Filozofia analityczna" "Matematyka Euklidesowa"
colnames(oceny_matrix)
## [1] "Semestr 1" "Semestr 2"
dimnames(oceny_matrix)
## [[1]]
## [1] "Statystyka w R" "Filozofia analityczna" "Matematyka Euklidesowa"
##
## [[2]]
## [1] "Semestr 1" "Semestr 2"
nrow(oceny_matrix)
## [1] 3
ncol(oceny_matrix)
## [1] 2
dim(oceny_matrix)
## [1] 3 2
Rozszerzanie ramki
# zapomnieliśmy o kulturze ciała, skupiając się na kulturze umysłu
wych_fiz <- c(6,6)
# dodajmy zatem nowy przedmiot do naszej ramki
oceny_matrix <- rbind(oceny_matrix, wych_fiz)
oceny_matrix
## Semestr 1 Semestr 2
## Statystyka w R 2 3
## Filozofia analityczna 5 5
## Matematyka Euklidesowa 4 4
## wych_fiz 6 6
# poprawmy nazwę przedmiotu (jesteśmy wszakże estetami)
rownames(oceny_matrix)[4] <- c("Wychowanie fizyczne")
# obliczmy średnią ocen ponownie, przypiszmy do zmiennej
srednia_ocen <- rowMeans(oceny_matrix)
srednia_ocen
## Statystyka w R Filozofia analityczna Matematyka Euklidesowa
## 2.5 5.0 4.0
## Wychowanie fizyczne
## 6.0
# dodajmy podsumowującą kolumnę do ramki
oceny_matrix <- cbind(oceny_matrix, srednia_ocen)
oceny_matrix
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 2 3 2.5
## Filozofia analityczna 5 5 5.0
## Matematyka Euklidesowa 4 4 4.0
## Wychowanie fizyczne 6 6 6.0
# a jak nam szło w poszczególnych semestrach?
colMeans(oceny_matrix)
## Semestr 1 Semestr 2 srednia_ocen
## 4.250 4.500 4.375
Wyciąganie elementów z matrycy
# Pani mówi, że 'włef' nie liczy się do średniej :(
dim(oceny_matrix)
## [1] 4 3
oceny_matrix2 <- oceny_matrix[1:3,] # wyrzucamy w-f
oceny_matrix2
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 2 3 2.5
## Filozofia analityczna 5 5 5.0
## Matematyka Euklidesowa 4 4 4.0
srednia_semestr <- (colMeans(oceny_matrix2)) # obliczamy ponownie średnie semestralne
# i dodajemy do naszej ramki
oceny_matrix2 <- rbind(oceny_matrix2, srednia_semestr)
oceny_matrix2
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 2.000000 3 2.500000
## Filozofia analityczna 5.000000 5 5.000000
## Matematyka Euklidesowa 4.000000 4 4.000000
## srednia_semestr 3.666667 4 3.833333
# przypominam o tym, że jesteśmy estetami
colnames(oceny_matrix2)[3] <- "Średnia ocen z semestru"
oceny_matrix2
## Semestr 1 Semestr 2 Średnia ocen z semestru
## Statystyka w R 2.000000 3 2.500000
## Filozofia analityczna 5.000000 5 5.000000
## Matematyka Euklidesowa 4.000000 4 4.000000
## srednia_semestr 3.666667 4 3.833333
# Pan od w-f ogarnął się, że na studiach nie ma szóstek, to nie podstawówka
oceny_matrix[4,1:2] <- oceny_matrix[4,1:2] - 1
oceny_matrix
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 2 3 2.5
## Filozofia analityczna 5 5 5.0
## Matematyka Euklidesowa 4 4 4.0
## Wychowanie fizyczne 5 5 6.0
# a Pan od R'a dostał poprawiony, tym razem zrobiony samodzielnie, projekt z Rmarkdown'a
oceny_matrix[1,1] <- 3.5
oceny_matrix
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 3.5 3 2.5
## Filozofia analityczna 5.0 5 5.0
## Matematyka Euklidesowa 4.0 4 4.0
## Wychowanie fizyczne 5.0 5 6.0
# tylko średnie trzeba by ponownie przeliczyć i podmienić
oceny_matrix[1,3] <- mean(c(oceny_matrix[1,1], oceny_matrix[1,2])) # funkcja mean()
oceny_matrix
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 3.5 3 3.25
## Filozofia analityczna 5.0 5 5.00
## Matematyka Euklidesowa 4.0 4 4.00
## Wychowanie fizyczne 5.0 5 6.00
Skoro już napinamy muskuły, że jesteśmy tacy schludni i perfekcyjni, to stwierdzamy, że drażni nas, że R zrobił nam z dwóch kolumn liczby wysokiej precyzji (typu double, numeric, what ever language do you use) i duża liczba znaków się nam wyświetla
# przypomnijmy sobie kształt ramki
oceny_matrix2
## Semestr 1 Semestr 2 Średnia ocen z semestru
## Statystyka w R 2.000000 3 2.500000
## Filozofia analityczna 5.000000 5 5.000000
## Matematyka Euklidesowa 4.000000 4 4.000000
## srednia_semestr 3.666667 4 3.833333
# poznajmy round()
oceny_matrix2[,1] <- round(oceny_matrix2[,1], 2)
oceny_matrix2[,3] <- round(oceny_matrix2[,1], 2)
oceny_matrix2 # much better
## Semestr 1 Semestr 2 Średnia ocen z semestru
## Statystyka w R 2.00 3 2.00
## Filozofia analityczna 5.00 5 5.00
## Matematyka Euklidesowa 4.00 4 4.00
## srednia_semestr 3.67 4 3.67
round()
# btw
x <- 123.456789
round(x, digits = 2) # 123.46 (2 miejsca po przecinku)
## [1] 123.46
round(x, digits = 1) # 123.5 (1 miejsce po przecinku)
## [1] 123.5
round(x, digits = 0) # 123 (liczba całkowita)
## [1] 123
round(x, digits = -1) # 120 (zaokrąglenie do dziesiątek, do wielokrotności 10**2)
## [1] 120
round(x, digits = -2) # 100 (zaokrąglenie do setek)
## [1] 100
round(x, digits = -3) # 0 (zaokrąglenie do tysięcy)
## [1] 0
I taka jeszcze własność matryc
oceny_matrix # przypomnijmy sobie kształt naszej ramki
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 3.5 3 3.25
## Filozofia analityczna 5.0 5 5.00
## Matematyka Euklidesowa 4.0 4 4.00
## Wychowanie fizyczne 5.0 5 6.00
# koleżanka nie lubi kolegi, nie odpowiedział na jej afekt, a że jest kocórką IT, zhakowała USOS i obniżyła mu oceny ze wszystkich przedmiotów
oceny_matrix - 1
## Semestr 1 Semestr 2 srednia_ocen
## Statystyka w R 2.5 2 2.25
## Filozofia analityczna 4.0 4 4.00
## Matematyka Euklidesowa 3.0 3 3.00
## Wychowanie fizyczne 4.0 4 5.00
# szczęśliwie nie nadpisała wyników ;)
oceny_matrix[oceny_matrix == 4]
## [1] 4 4 4
which(oceny_matrix == 4, arr.ind = TRUE)
## row col
## Matematyka Euklidesowa 3 1
## Matematyka Euklidesowa 3 2
## Matematyka Euklidesowa 3 3
Drobny wtręt. Badając klasę (class()
) macierzy
otrzymaliśmy informację, że nasz obiekt to zarówno matrix
,
jak i array
. Krótka różnica między dwoma obiektami na
przykładzie poniżej:
# Macierz 2x3
(macierz_przyklad <- matrix(data = 1:6,
nrow = 2,
ncol = 3)
)
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
# Tablica - # Array z 3 wymiarami (wiersze × kolumny × "warstwy")
(tablica_przyklad <- array(1:24, dim = c(3, 4, 2)))
## , , 1
##
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
##
## , , 2
##
## [,1] [,2] [,3] [,4]
## [1,] 13 16 19 22
## [2,] 14 17 20 23
## [3,] 15 18 21 24
# To tworzy strukturę:
# - 3 wiersze
# - 4 kolumny
# - 2 "warstwy" (można myśleć o tym jak o dwóch matrycach 3×4)
Główną różnicą między tymi dwoma obiektami jest to, że macierz
(matrix
) jest szczególnym, bo dwuwymiarowym typem tablicy
(array
). Tablica jest co do zasady wielowymiarową strukturą
danych, która - ważne zastrzeżenie - przechowuje elementy tego
samego typu (w przeciwieństwie do listy, która co prawda jest
jednowymiarowa, ale może przechowywać elementy różnych typów, a zatem
również listy, co de facto czynią ją w jakimś sensie
wielowymiarową… bełkot, szczegóły później).
“Dane o sprzedaży”
# Wyobraźmy sobie dane o sprzedaży:
# - 3 produkty (wiersze)
# - 4 kwartały (kolumny)
# - 2 lata (trzeci wymiar)
sprzedaz <- array(
data = c(100, 150, 200, 120, 180, 220, 110, 160, 210, 130, 170, 230,
105, 155, 205, 125, 185, 225, 115, 165, 215, 135, 175, 235),
dim = c(3, 4, 2),
dimnames = list(
Produkt = c("A", "B", "C"),
Kwartal = c("Q1", "Q2", "Q3", "Q4"),
Rok = c("2023", "2024")
)
)
print(sprzedaz)
## , , Rok = 2023
##
## Kwartal
## Produkt Q1 Q2 Q3 Q4
## A 100 120 110 130
## B 150 180 160 170
## C 200 220 210 230
##
## , , Rok = 2024
##
## Kwartal
## Produkt Q1 Q2 Q3 Q4
## A 105 125 115 135
## B 155 185 165 175
## C 205 225 215 235
# Dostęp do danych z 2024 roku
sprzedaz[, , "2024"]
## Kwartal
## Produkt Q1 Q2 Q3 Q4
## A 105 125 115 135
## B 155 185 165 175
## C 205 225 215 235
# Sprzedaż produktu B w Q2 w 2023
sprzedaz["B", "Q2", "2023"]
## [1] 180
# Wszystkie kwartały produktu A w 2024
sprzedaz["A", , "2024"]
## Q1 Q2 Q3 Q4
## 105 125 115 135
“Dane klimatyczne”
# Temperatura w 12 miastach, przez 365 dni, przez 5 lat
temperatura <- array(
data = rnorm(12 * 365 * 5, mean = 15, sd = 8), # ?rnorm
dim = c(12, 365, 5),
dimnames = list(
Miasto = paste("Miasto", 1:12), # paste()
Dzien = paste("Dzien", 1:365),
Rok = 2020:2024
)
)
# Średnia temperatura w Mieście 1 w 2023 roku
mean(temperatura["Miasto 1", , "2023"])
## [1] 14.27825
# Średnia temperatura w 100. dniu we wszystkich miastach i latach
mean(temperatura[, "Dzien 100", ])
## [1] 13.64846
# Temperatura w pierwszych 7 dniach 2024 we wszystkich miastach
temperatura[, 1:7, "2024"]
## Dzien
## Miasto Dzien 1 Dzien 2 Dzien 3 Dzien 4 Dzien 5 Dzien 6
## Miasto 1 14.473869 -1.551787 19.79363169 14.4381710 8.918001 8.533684
## Miasto 2 14.044740 18.297673 18.71871307 28.3521016 25.675413 5.279035
## Miasto 3 18.791663 18.093304 25.47361742 26.2767049 10.682710 30.669667
## Miasto 4 3.852931 7.698747 17.50966918 11.7801681 20.536229 12.262536
## Miasto 5 37.544346 10.947059 10.44449749 15.3624909 4.577420 8.899487
## Miasto 6 11.546584 23.632032 11.83750548 17.5142275 22.056840 24.029481
## Miasto 7 10.662979 10.529199 7.52618951 14.9028578 4.177482 17.069458
## Miasto 8 -2.192245 2.150525 0.06323819 24.0170482 22.147729 7.670347
## Miasto 9 12.301732 9.559002 13.29824284 13.6136358 29.795179 7.068208
## Miasto 10 9.290747 22.288937 11.09591696 28.2043316 15.198680 1.856036
## Miasto 11 13.559546 1.996519 8.93664205 13.4222434 22.663044 22.815649
## Miasto 12 27.219777 9.128440 14.69095951 -0.5082137 20.378205 3.125952
## Dzien
## Miasto Dzien 7
## Miasto 1 4.221015
## Miasto 2 24.983083
## Miasto 3 15.410208
## Miasto 4 9.414400
## Miasto 5 17.284862
## Miasto 6 12.244926
## Miasto 7 7.813790
## Miasto 8 17.794933
## Miasto 9 26.596484
## Miasto 10 29.048825
## Miasto 11 10.020744
## Miasto 12 19.022158
Factor to tzw. zmienna kategorialna - nominalna bądź porządkowa.
Dane kategorialne (jakościowe) to takie, które przyjmują wartości z ograniczonego zestawu kategorii.
Przykłady:
Płeć: “kobieta”, “mężczyzna”
Grupa krwi: “A”, “B”, “AB”, “0”
Poziom wykształcenia: “podstawowe”, “średnie”, “wyższe”
Ocena: “niedostateczny”, “dostateczny”, “dobry”, “bardzo dobry”, “celujący”
* Nominalna
# Zdefiniujmy 'zwykły' wektor zawierający płcie
# (załóżmy, omijając zgrabnie współczesne dywagacje, że mamy dwie płcie)
(sex_vector <- c("Mężczyzna", "Kobieta", "Kobieta", "Mężczyzna", "Mężczyzna"))
## [1] "Mężczyzna" "Kobieta" "Kobieta" "Mężczyzna" "Mężczyzna"
# skonwertujmy typ zmiennej na factor, przypiszmy do nowej zmiennej i zobaczmy rezultat
(factor_sex_vector <- as.factor(sex_vector))
## [1] Mężczyzna Kobieta Kobieta Mężczyzna Mężczyzna
## Levels: Kobieta Mężczyzna
* Porządkowa
temperatura_vector <- c("Wysoka", "Niska", "Wysoka","Niska", "Średnia")
factor_temperatura_vector <- factor(temperatura_vector,
order = TRUE, # dookreślamy zarówno czy jest to zmienna porządkowa
levels = c("Niska", "Średnia", "Wysoka")) # oraz jak ten porządek rzeczy się układa
factor_temperatura_vector
## [1] Wysoka Niska Wysoka Niska Średnia
## Levels: Niska < Średnia < Wysoka
# Możemy sprawdzić liczbę poziomów w następujący sposób
nlevels(factor_temperatura_vector)
## [1] 3
Poziomy zmiennej
# tworzymy wektor
vector_plci <- c("M", "F", "F", "M", "M")
# 'faktoryzujemy' go
factor_vector_plci <- as.factor(vector_plci)
# w kolejnym kroku nazywamy poziomy
levels(factor_vector_plci) <- c("Kobieta", "Mężczyzna") # nieco podobnie jak nazywaliśmy elementy wektora funkcją names()
# i otrzymujemy
factor_vector_plci
## [1] Mężczyzna Kobieta Kobieta Mężczyzna Mężczyzna
## Levels: Kobieta Mężczyzna
# zobaczmy różnice w podsumowaniu pozornie identycznych obiektów
summary(vector_plci)
## Length Class Mode
## 5 character character
summary(factor_vector_plci)
## Kobieta Mężczyzna
## 2 3
‘Subtelna’ własność kategorialnej zmiennej porządkowej
gosciu <- factor_vector_plci[1]
gosciuwa <- factor_vector_plci[2]
# czy facet jest "silniejszy"/większy od kobiety? Sprawdźmy operatorem >
gosciu > gosciuwa
## Warning in Ops.factor(gosciu, gosciuwa): '>' not meaningful for factors
## [1] NA
# ale co z temperaturą? Czy średnia jest niższa niż wysoka?
srednia <- temperatura_vector[5]
wysoka <- temperatura_vector[1]
srednia < wysoka # zaiste :P
## [1] TRUE
Table częstości - zliczanie wystąpień
# factor
(kolory <- factor(c("czerwony", "niebieski","czerwony", "czerwony", "zielony",
"niebieski", "czerwony", "zielony","czerwony", "niebieski")))
## [1] czerwony niebieski czerwony czerwony zielony niebieski czerwony
## [8] zielony czerwony niebieski
## Levels: czerwony niebieski zielony
# wygląda jak tabela częstości
summary(kolory)
## czerwony niebieski zielony
## 5 3 2
# Tabela częstości - "jawnie"
table(kolory)
## kolory
## czerwony niebieski zielony
## 5 3 2
# Proporcje
prop.table(table(kolory)) # ?prop.table
## kolory
## czerwony niebieski zielony
## 0.5 0.3 0.2
# Procenty
prop.table(table(kolory)) * 100
## kolory
## czerwony niebieski zielony
## 50 30 20
# Dane
plec <- factor(c("K", "M", "K", "M", "K", "M", "K", "M"))
kierunek <- factor(c("Info", "Info", "Mat", "Mat", "Info", "Fiz", "Mat", "Fiz"))
# Tabela krzyżowa
table(plec, kierunek)
## kierunek
## plec Fiz Info Mat
## K 0 2 2
## M 2 1 1
# Z proporcjami
prop.table(table(plec, kierunek))
## kierunek
## plec Fiz Info Mat
## K 0.000 0.250 0.250
## M 0.250 0.125 0.125
# Proporcje w wierszach
prop.table(table(plec, kierunek), margin = 1)
## kierunek
## plec Fiz Info Mat
## K 0.00 0.50 0.50
## M 0.50 0.25 0.25
# Proporcje w kolumnach
prop.table(table(plec, kierunek), margin = 2)
## kierunek
## plec Fiz Info Mat
## K 0.0000000 0.6666667 0.6666667
## M 1.0000000 0.3333333 0.3333333
Modyfikowanie faktorów
# Tworzenie faktora
oceny <- factor(c("dobry", "dostateczny", "bardzo dobry", "dobry"))
# Dodanie nowego elementu - trzeba najpierw dodać poziom!
oceny[5] <- "celujący" # Ostrzeżenie! Powstaje NA
## Warning in `[<-.factor`(`*tmp*`, 5, value = "celujący"): invalid factor level,
## NA generated
# Prawidłowy sposób:
levels(oceny) <- c(levels(oceny), "celujący")
oceny[5] <- "celujący"
print(oceny)
## [1] dobry dostateczny bardzo dobry dobry celujący
## Levels: bardzo dobry dobry dostateczny celujący
# Usunięcie nieużywanych poziomów
oceny <- factor(c("dobry", "dostateczny", "bardzo dobry", "dobry"))
oceny <- oceny[oceny != "bardzo dobry"] # Usunięcie elementu
print(levels(oceny)) # "bardzo dobry" nadal jest poziomem!
## [1] "bardzo dobry" "dobry" "dostateczny"
oceny <- droplevels(oceny) # Usunięcie nieużywanych poziomów
print(levels(oceny))
## [1] "dobry" "dostateczny"
Dodawanie nowych wartości
kolor <- factor(c("czerwony", "niebieski"))
kolor[3] <- "zielony" # Ostrzeżenie! Powstaje NA
## Warning in `[<-.factor`(`*tmp*`, 3, value = "zielony"): invalid factor level,
## NA generated
kolor
## [1] czerwony niebieski <NA>
## Levels: czerwony niebieski
# Najpierw dodaj poziom:
levels(kolor) <- c(levels(kolor), "zielony")
kolor[3] <- "zielony" # Teraz działa
Konwersja typów
# Factor na character
(oceny <- factor(c("dobry", "dostateczny", "bardzo dobry"))); class(oceny)
## [1] dobry dostateczny bardzo dobry
## Levels: bardzo dobry dobry dostateczny
## [1] "factor"
oceny_text <- as.character(oceny)
print(oceny_text)
## [1] "dobry" "dostateczny" "bardzo dobry"
class(oceny_text)
## [1] "character"
# Factor na numeric - UWAGA!
liczby_f <- factor(c("10", "20", "5", "15"))
as.numeric(liczby_f) # BŁĄD! Daje 1, 3, 2, 4 (indeksy poziomów!)
## [1] 1 3 4 2
# Prawidłowa konwersja:
as.numeric(as.character(liczby_f)) # Daje 10, 20, 5, 15
## [1] 10 20 5 15
# Character na factor
tekst <- c("jabłko", "gruszka", "jabłko", "śliwka")
owoce <- as.factor(tekst)
print(owoce)
## [1] jabłko gruszka jabłko śliwka
## Levels: gruszka jabłko śliwka
Zmiana kolejności poziomów
# Oryginalny factor
oceny <- factor(c("dobry", "dostateczny", "bardzo dobry", "celujący"))
print(levels(oceny)) # Alfabetycznie
## [1] "bardzo dobry" "celujący" "dobry" "dostateczny"
# Zmiana kolejności poziomów
oceny <- factor(oceny,
levels = c("niedostateczny", "dostateczny", "dopuszczający",
"dobry", "bardzo dobry", "celujący"))
print(levels(oceny))
## [1] "niedostateczny" "dostateczny" "dopuszczający" "dobry"
## [5] "bardzo dobry" "celujący"
# Odwrócenie kolejności
oceny_odwrocone <- factor(oceny, levels = rev(levels(oceny)))
print(levels(oceny_odwrocone))
## [1] "celujący" "bardzo dobry" "dobry" "dopuszczający"
## [5] "dostateczny" "niedostateczny"
# R domyślnie sortuje poziomy alfabetycznie
miesiace <- factor(c("Styczeń", "Luty", "Marzec"))
print(levels(miesiace)) # Alfabetycznie!
## [1] "Luty" "Marzec" "Styczeń"
# Określ właściwą kolejność:
miesiace <- factor(miesiace,
levels = c("Styczeń", "Luty", "Marzec", "Kwiecień",
"Maj", "Czerwiec", "Lipiec", "Sierpień",
"Wrzesień", "Październik", "Listopad", "Grudzień"))
plec <- as.factor(c("M", "K", "M", "K", "K"))
levels(plec) <- c("Kobieta","Mężczyzna") # skąd on to wie?
summary(plec)
## Kobieta Mężczyzna
## 3 2
levels(plec) <- c("Mężczyzna", "Kobieta") # skąd on to wie lub nie?
summary(plec)
## Mężczyzna Kobieta
## 3 2
# Najlepszy sposób - od razu określ właściwą kolejność
plec <- factor(c("M", "K", "M", "K", "K"),
levels = c("K", "M"),
labels = c("Kobieta", "Mężczyzna"))
summary(plec)
## Kobieta Mężczyzna
## 3 2
# jaka jest logika przypisania?
x <- factor(c("Ź", "A", "C"))
levels(x) <- c("pierwszy", "drugi", "trzeci")
print(x)
## [1] trzeci pierwszy drugi
## Levels: pierwszy drugi trzeci
# Odpowiedź:
# [1] trzeci pierwszy drugi
# Levels: pierwszy drugi trzeci
# Dlaczego?
# Alfabetycznie: "A" < "C" < "Ź" (polskie znaki na końcu!)
# Więc: A=1, C=2, Ź=3
# Po zmianie: A="pierwszy", C="drugi", Ź="trzeci"
Data frame
w R to dwuwymiarowa struktura danych, która
jest jedną z najczęściej używanych do przechowywania i manipulacji
danymi. Można ją porównać do tabeli w bazie danych lub arkusza
kalkulacyjnego, gdzie dane są zorganizowane w wiersze i kolumny.
Kluczowe cechy:
Każda kolumna może mieć inny typ danych (numeric, character, logical, factor)
Wszystkie kolumny muszą mieć taką samą długość
Wiersze i kolumny mogą mieć nazwy
Okazuje się, że mamy pod ręką kilka zbiorów danych by
default. Ramką, którą zna każdy R’owiec jest m.in.
zestaw mtcars
Obejrzyjmy dokumentację,
żeby sprawdzić co zawiera: https://www.rdocumentation.org/packages/datasets/versions/3.6.2/topics/mtcars
a następnie obejrzyjmy ją w konsoli
mtcars
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
Zabieg ten bywa niekiedy głupotą przy większych zbiorach.
Posprawdzajmy ten zbiór “rezolutniej”, odpowiednimi funkcjami.
str(mtcars) # czy to w ogóle jest data.frame?
## 'data.frame': 32 obs. of 11 variables:
## $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
## $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
## $ disp: num 160 160 108 258 360 ...
## $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
## $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
## $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
## $ qsec: num 16.5 17 18.6 19.4 17 ...
## $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
## $ am : num 1 1 1 0 0 0 0 0 0 0 ...
## $ gear: num 4 4 4 3 3 3 3 4 4 4 ...
## $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
# można sprawdzić jeszcze inaczej
is.data.frame(mtcars)
## [1] TRUE
head(mtcars) # może pierwsze kilka wierszy, żeby nie zaśmiecać konsoli
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
tail(mtcars, 2) # ostatnie 2 wiersze
## mpg cyl disp hp drat wt qsec vs am gear carb
## Maserati Bora 15.0 8 301 335 3.54 3.57 14.6 0 1 5 8
## Volvo 142E 21.4 4 121 109 4.11 2.78 18.6 1 1 4 2
Wymiary data.frame
nrow(mtcars) # liczba wierszy
## [1] 32
ncol(mtcars) # liczba kolumn
## [1] 11
dim(mtcars) # wymiary: [wiersze, kolumny]
## [1] 32 11
Nazwy kolumn i wierszy
# Nazwy kolumn
colnames(mtcars)
## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
## [11] "carb"
names(mtcars) # to samo co colnames()
## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
## [11] "carb"
# Nazwy wierszy
rownames(mtcars)
## [1] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710"
## [4] "Hornet 4 Drive" "Hornet Sportabout" "Valiant"
## [7] "Duster 360" "Merc 240D" "Merc 230"
## [10] "Merc 280" "Merc 280C" "Merc 450SE"
## [13] "Merc 450SL" "Merc 450SLC" "Cadillac Fleetwood"
## [16] "Lincoln Continental" "Chrysler Imperial" "Fiat 128"
## [19] "Honda Civic" "Toyota Corolla" "Toyota Corona"
## [22] "Dodge Challenger" "AMC Javelin" "Camaro Z28"
## [25] "Pontiac Firebird" "Fiat X1-9" "Porsche 914-2"
## [28] "Lotus Europa" "Ford Pantera L" "Ferrari Dino"
## [31] "Maserati Bora" "Volvo 142E"
Zmiana nazw kolumn bądź wierszy
polskie_nazwy_mtcars <- c(
"MilePerGalon", # mpg - Zużycie paliwa (mil na galon)
"Cylindry", # cyl - Liczba cylindrów
"Pojemnosc", # disp - Pojemność skokowa silnika
"KonieMechaniczne",# hp - Moc (koni mechanicznych)
"PrzelozenieOsi", # drat - Przełożenie osi
"Waga", # wt - Masa własna (w tysiącach funtów)
"Czas1/4mili", # qsec - Czas przejazdu 1/4 mili
"SilnikVS", # vs - Typ silnika: (0 = w kształcie V, 1 = prosty)
"SkrzyniaBiegow", # am - Typ skrzyni biegów: (0 = automatyczna, 1 = manualna)
"Biegi", # gear - Liczba biegów (przełożeń do przodu)
"Gazniki" # carb - Liczba gaźników
)
colnames(mtcars) <- polskie_nazwy_mtcars
rownames(mtcars)[18] <- "Taki Maluch"
Stwórzmy własny data.frame from scratch
# Tworzenie prostego data.frame
df <- data.frame(
imie = c("Anna", "Jan", "Maria", "Piotr"),
wiek = c(23, 25, 22, 24),
ocena = c(4.5, 3.5, 5.0, 4.0)
)
print(df)
## imie wiek ocena
## 1 Anna 23 4.5
## 2 Jan 25 3.5
## 3 Maria 22 5.0
## 4 Piotr 24 4.0
Albo z istniejących wektorów.
# pojedyncze wektory, które staną się zmiennymi
name <- c("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune")
type <- c("Terrestrial planet", "Terrestrial planet", "Terrestrial planet", "Terrestrial planet", "Gas giant", "Gas giant", "Gas giant", "Gas giant")
diameter <- c(0.382, 0.949, 1, 0.532, 11.209, 9.449, 4.007, 3.883)
rotation <- c(58.64, -243.02, 1, 1.03, 0.41, 0.43, -0.72, 0.67)
rings <- c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE)
# sklejenie wektorów w data.frame
planets_df <- data.frame(name,
type,
diameter,
rotation,
rings)
rm(name, type, diameter, rotation, rings) # mogę usunę zbędne już wektory ze środowiska
str(planets_df)
## 'data.frame': 8 obs. of 5 variables:
## $ name : chr "Mercury" "Venus" "Earth" "Mars" ...
## $ type : chr "Terrestrial planet" "Terrestrial planet" "Terrestrial planet" "Terrestrial planet" ...
## $ diameter: num 0.382 0.949 1 0.532 11.209 ...
## $ rotation: num 58.64 -243.02 1 1.03 0.41 ...
## $ rings : logi FALSE FALSE FALSE FALSE TRUE TRUE ...
planets_df
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
## 5 Jupiter Gas giant 11.209 0.41 TRUE
## 6 Saturn Gas giant 9.449 0.43 TRUE
## 7 Uranus Gas giant 4.007 -0.72 TRUE
## 8 Neptune Gas giant 3.883 0.67 TRUE
Wybierzmy z ramki jakieś interesujące nas informacje
# znajdźmy średnicę Ziemi
planets_df[3,3] # trzeci wiersz, trzecia kolumna
## [1] 1
# czy na Marsie da się mieszkać? Nie wiem, ale przyjrzyjmy się wszystkim informacjom na jego temat, którymi dysponujemy
planets_df[4,] # czwarty wiersz
## name type diameter rotation rings
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
# Średnice pierwszych trzech planet
planets_df[1:3, "diameter"]
## [1] 0.382 0.949 1.000
# Średnice pierwszych trzech planet - alternatywnie
planets_df[1:3,3] # Zapytają Państwo, która metoda jest lepsza? Odp.: to zależy...
## [1] 0.382 0.949 1.000
# Cała kolumna
planets_df[, 2] # druga kolumna
## [1] "Terrestrial planet" "Terrestrial planet" "Terrestrial planet"
## [4] "Terrestrial planet" "Gas giant" "Gas giant"
## [7] "Gas giant" "Gas giant"
# Wiele wierszy lub kolumn
planets_df[1:3, ] # wiersze 1-3
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
planets_df[, c(1:3)] # kolumny od 1 do 3
## name type diameter
## 1 Mercury Terrestrial planet 0.382
## 2 Venus Terrestrial planet 0.949
## 3 Earth Terrestrial planet 1.000
## 4 Mars Terrestrial planet 0.532
## 5 Jupiter Gas giant 11.209
## 6 Saturn Gas giant 9.449
## 7 Uranus Gas giant 4.007
## 8 Neptune Gas giant 3.883
planets_df[, c(1, 3)] # kolumny 1 i 3
## name diameter
## 1 Mercury 0.382
## 2 Venus 0.949
## 3 Earth 1.000
## 4 Mars 0.532
## 5 Jupiter 11.209
## 6 Saturn 9.449
## 7 Uranus 4.007
## 8 Neptune 3.883
planets_df[c(1, 3), c(1, 2)] # wybrane wiersze i kolumny
## name type
## 1 Mercury Terrestrial planet
## 3 Earth Terrestrial planet
Wyrzuciliśmy wcześniej z workspace’u wszystkie wektory tworzące
zbiór planet. Teraz jednak potrzebujemy pod ręką niektórych. Zreplikujmy
je używając naszego data.frame’u
name_vector <- planets_df$name
rings_vector <- planets_df$rings
Wybieranie wierszy z uwagi na warunek
# Pani od wuefu powiedziała, że nie da się biegać na gazowych planetach, zatem na których planetach można?
planets_df[planets_df$type == "Terrestrial planet",]
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
# Oraz, że lepiej biegać na tych bez ringu ("Bo jeszcze na łeb spadnie" - cytuję)
planets_df[rings_vector == F,]
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
# czyli na obu nie bardzo?
planets_df[planets_df$rings != T & planets_df$type != "Gas giant",] # omówmy
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
# które planety mają średnicę mniejszą niż ziemska?
subset(planets_df, subset = diameter <1)
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
# nasza ramka jest ułożona w porządku występowania względem Słońca, ustawmy ją w kolejności leksykalnej
pozycja <- order(planets_df$name)
planets_df[pozycja,]
## name type diameter rotation rings
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
## 5 Jupiter Gas giant 11.209 0.41 TRUE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 8 Neptune Gas giant 3.883 0.67 TRUE
## 6 Saturn Gas giant 9.449 0.43 TRUE
## 7 Uranus Gas giant 4.007 -0.72 TRUE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
# albo względem wielkości. Która zmienna odpowiada za "gabaryty" planety?
pozycja <- order(planets_df$diameter)
planets_df[pozycja,]
## name type diameter rotation rings
## 1 Mercury Terrestrial planet 0.382 58.64 FALSE
## 4 Mars Terrestrial planet 0.532 1.03 FALSE
## 2 Venus Terrestrial planet 0.949 -243.02 FALSE
## 3 Earth Terrestrial planet 1.000 1.00 FALSE
## 8 Neptune Gas giant 3.883 0.67 TRUE
## 7 Uranus Gas giant 4.007 -0.72 TRUE
## 6 Saturn Gas giant 9.449 0.43 TRUE
## 5 Jupiter Gas giant 11.209 0.41 TRUE
Dodanie nowej kolumny
planets_df$DaSieMieszkac <- c(F,F,T,T,F,F,F,F)
Dodanie nowego wiersza
nowa_planeta <- data.frame(
name = "Maluch's Best Planet",
type = "Terrestrial planet",
diameter = 1.000,
rotation = 1.00,
rings = T,
DaSieMieszkac = T
)
planets_df <- rbind(planets_df, nowa_planeta)
Modyfikacja wartości
planets_df[-9, "rings"] <- FALSE
Usunięcie kolumny lub wiersza
planets_df$DaSieMieszkac <- NULL
planets_df <- planets_df[-9, ]
Przydatne
# Unikalne wartości
unique(planets_df$type)
## [1] "Terrestrial planet" "Gas giant"
# Liczba unikalnych wartości
length(unique(planets_df$rings))
## [1] 1
Podsumowania i statystyki
# Podsumowanie statystyczne
summary(mtcars)
## MilePerGalon Cylindry Pojemnosc KonieMechaniczne
## Min. :10.40 Min. :4.000 Min. : 71.1 Min. : 52.0
## 1st Qu.:15.43 1st Qu.:4.000 1st Qu.:120.8 1st Qu.: 96.5
## Median :19.20 Median :6.000 Median :196.3 Median :123.0
## Mean :20.09 Mean :6.188 Mean :230.7 Mean :146.7
## 3rd Qu.:22.80 3rd Qu.:8.000 3rd Qu.:326.0 3rd Qu.:180.0
## Max. :33.90 Max. :8.000 Max. :472.0 Max. :335.0
## PrzelozenieOsi Waga Czas1/4mili SilnikVS
## Min. :2.760 Min. :1.513 Min. :14.50 Min. :0.0000
## 1st Qu.:3.080 1st Qu.:2.581 1st Qu.:16.89 1st Qu.:0.0000
## Median :3.695 Median :3.325 Median :17.71 Median :0.0000
## Mean :3.597 Mean :3.217 Mean :17.85 Mean :0.4375
## 3rd Qu.:3.920 3rd Qu.:3.610 3rd Qu.:18.90 3rd Qu.:1.0000
## Max. :4.930 Max. :5.424 Max. :22.90 Max. :1.0000
## SkrzyniaBiegow Biegi Gazniki
## Min. :0.0000 Min. :3.000 Min. :1.000
## 1st Qu.:0.0000 1st Qu.:3.000 1st Qu.:2.000
## Median :0.0000 Median :4.000 Median :2.000
## Mean :0.4062 Mean :3.688 Mean :2.812
## 3rd Qu.:1.0000 3rd Qu.:4.000 3rd Qu.:4.000
## Max. :1.0000 Max. :5.000 Max. :8.000
# Statystyki dla konkretnych kolumn
mean(mtcars$cyl) # średnia liczba cylindrów
## Warning in mean.default(mtcars$cyl): argument is not numeric or logical:
## returning NA
## [1] NA
median(mtcars$hp) # mediana liczby koni mechanicznych
## NULL
sd(mtcars$wt) # odchylenie standardowe masy własnej
## [1] NA
min(mtcars$gear) # minimum liczby biegów
## Warning in min(mtcars$gear): no non-missing arguments to min; returning Inf
## [1] Inf
max(mtcars$carb) # maksimum liczny gaźników
## Warning in max(mtcars$carb): no non-missing arguments to max; returning -Inf
## [1] -Inf
# Tabele częstości
table(mtcars$cyl)
## < table of extent 0 >
Zadania przy tablicy
data.frame
ksiazki
z informacjami o
5 ulubionych książkach (tytuł, autor, rok wydania, ocena)ksiazki <- data.frame(
tytul = c(
"Mistrz i Małgorzata",
"1984",
"Wiedźmin: Ostatnie życzenie",
"Harry Potter i Kamień Filozoficzny",
"Hobbit"
),
autor = c(
"Michaił Bułhakow",
"George Orwell",
"Andrzej Sapkowski",
"J.K. Rowling",
"J.R.R. Tolkien"
),
rok_wydania = c(1967, 1949, 1993, 1997, 1937),
ocena = c(4.8, 4.5, 4.7, 4.9, 4.6)
)
TRUE
/FALSE
)ksiazki$przeczytana <- c(TRUE, TRUE, TRUE, FALSE, TRUE)
ksiazki_po_2010 <- ksiazki[ksiazki$rok_wydania > 1995, ]
ksiazki_po_2010_alt <- subset(ksiazki, rok_wydania > 1995)
ksiazki_posortowane <- ksiazki[order(ksiazki$ocena, decreasing = TRUE), ]
ksiazki_posortowane_alt <- ksiazki[order(-ksiazki$ocena), ]
# Przypomnienie sort() vs order()
# Nasze oceny
ksiazki$ocena
# [1] 4.8 4.5 4.7 4.9 4.6
# sort() daje tylko wartości
sort(ksiazki$ocena, decreasing = TRUE)
# [1] 4.9 4.8 4.7 4.6 4.5
# order() daje pozycje
order(ksiazki$ocena, decreasing = TRUE)
# [1] 4 1 3 5 2
# Czyli: wiersz 4 (Harry Potter) ma najwyższą ocenę (4.9)
# Filtrujemy tylko przeczytane książki
przeczytane <- ksiazki[ksiazki$przeczytana == TRUE, ]
# Obliczamy średnią
(srednia_ocena_przeczytanych <- mean(przeczytane$ocena))
## [1] 4.65
nrow(ksiazki[ksiazki$przeczytana == TRUE, ])
## [1] 4
ksiazki$tytul[max(ksiazki$ocena)]
## [1] "Harry Potter i Kamień Filozoficzny"
Lista to najbardziej elastyczna struktura danych w R. W przeciwieństwie do wektorów, które mogą zawierać tylko elementy tego samego typu, lista może przechowywać:
różne typy danych (liczby, tekst, wartości logiczne)
obiekty o różnych długościach
inne struktury danych (wektory, macierze, ramki danych)
nawet inne listy!
Listy są szczególnie przydatne, gdy chcemy zgrupować różnorodne informacje w jeden obiekt.
Tworzenie list
Podstawowa składnia. Do tworzenia list używamy funkcji
list()
:
# Prosta lista z różnymi typami danych
moja_lista <- list(
imie = "Anna",
wiek = 25,
student = TRUE,
oceny = c(4.5, 5.0, 4.0, 5.0)
)
moja_lista
## $imie
## [1] "Anna"
##
## $wiek
## [1] 25
##
## $student
## [1] TRUE
##
## $oceny
## [1] 4.5 5.0 4.0 5.0
Lista bez nazw
Elementy listy nie muszą mieć nazw:
lista_bez_nazw <- list(
"Warszawa",
500000,
c("Polska", "Europa")
)
lista_bez_nazw
## [[1]]
## [1] "Warszawa"
##
## [[2]]
## [1] 5e+05
##
## [[3]]
## [1] "Polska" "Europa"
Zagnieżdżone listy
Lista może zawierać inne listy:
osoba <- list(
dane_osobowe = list(
imie = "Jan",
nazwisko = "Kowalski",
wiek = 30
),
adres = list(
miasto = "Kraków",
kod_pocztowy = "30-001"
)
)
osoba
## $dane_osobowe
## $dane_osobowe$imie
## [1] "Jan"
##
## $dane_osobowe$nazwisko
## [1] "Kowalski"
##
## $dane_osobowe$wiek
## [1] 30
##
##
## $adres
## $adres$miasto
## [1] "Kraków"
##
## $adres$kod_pocztowy
## [1] "30-001"
Dostęp do elementów listy
Istnieją trzy główne sposoby odwoływania się do elementów listy:
$
(dla nazwanych elementów)# Najczęściej używany sposób
moja_lista$imie
## [1] "Anna"
moja_lista$oceny
## [1] 4.5 5.0 4.0 5.0
[[]]
(zwraca element)# Przez nazwę
moja_lista[["wiek"]]
## [1] 25
# Przez indeks
moja_lista[[1]]
## [1] "Anna"
[]
(zwraca pod-listę)# Zwraca listę z jednym elementem
moja_lista[1]
## $imie
## [1] "Anna"
# Różnica między [] a [[]]
class(moja_lista[1]) # lista
## [1] "list"
class(moja_lista[[1]]) # character
## [1] "character"
Dostęp do zagnieżdżonych elementów
# Sposób 1: łańcuchowy operator $
osoba$dane_osobowe$imie
## [1] "Jan"
# Sposób 2: wielokrotne [[]]
osoba[["adres"]][["miasto"]]
## [1] "Kraków"
Modyfikacja list
moja_lista$wiek <- 26
moja_lista$wiek
## [1] 26
moja_lista$kierunek <- "Statystyka"
moja_lista$rok_studiow <- 3
# Sprawdzamy zaktualizowaną listę
names(moja_lista)
## [1] "imie" "wiek" "student" "oceny" "kierunek"
## [6] "rok_studiow"
moja_lista$rok_studiow <- NULL
names(moja_lista)
## [1] "imie" "wiek" "student" "oceny" "kierunek"
Podstawowe informacje
# Nazwy elementów
names(moja_lista)
## [1] "imie" "wiek" "student" "oceny" "kierunek"
# Długość listy (liczba elementów)
length(moja_lista)
## [1] 5
# Struktura listy
str(moja_lista)
## List of 5
## $ imie : chr "Anna"
## $ wiek : num 26
## $ student : logi TRUE
## $ oceny : num [1:4] 4.5 5 4 5
## $ kierunek: chr "Statystyka"
Przekształcanie list
liczby_lista <- list(a = 1, b = 2, c = 3)
liczby_lista
## $a
## [1] 1
##
## $b
## [1] 2
##
## $c
## [1] 3
wektor <- unlist(liczby_lista)
wektor
## a b c
## 1 2 3
dane_lista <- list(
imie = c("Anna", "Jan", "Ewa"),
wiek = c(25, 30, 28),
student = c(TRUE, FALSE, TRUE)
)
dane_lista
## $imie
## [1] "Anna" "Jan" "Ewa"
##
## $wiek
## [1] 25 30 28
##
## $student
## [1] TRUE FALSE TRUE
df <- as.data.frame(dane_lista)
df
## imie wiek student
## 1 Anna 25 TRUE
## 2 Jan 30 FALSE
## 3 Ewa 28 TRUE
Przechowywanie wyników analizy
# Symulacja danych
set.seed(123)
dane <- rnorm(100, mean = 50, sd = 10)
# Zapisanie różnych statystyk w jednej liście
analiza <- list(
dane_surowe = dane,
statystyki = list(
srednia = mean(dane),
mediana = median(dane),
odch_std = sd(dane)
),
histogram = hist(dane, plot = FALSE)
)
# Łatwy dostęp do wyników
analiza$statystyki$srednia
## [1] 50.90406
Przechowywanie modeli statystycznych
# Tworzenie danych
x <- 1:10
y <- 2 * x + rnorm(10)
# Model liniowy zwraca listę!
model <- lm(y ~ x)
# Możemy łatwo wyciągać informacje
class(model)
## [1] "lm"
names(model)
## [1] "coefficients" "residuals" "effects" "rank"
## [5] "fitted.values" "assign" "qr" "df.residual"
## [9] "xlevels" "call" "terms" "model"
model$coefficients
## (Intercept) x
## -0.4856184 2.0163219
Podsumowanie
Listy w R to potężne narzędzie, które pozwala:
Kluczowe operacje:
list(nazwa1 = wartość1, nazwa2 = wartość2)
lista$nazwa
, lista[[indeks]]
,
lista[indeks]
lista$nowy_element <- wartość
names()
, length()
,
str()
, etc.
Poniżej omówienie kilku przydatnych i popularnych funkcji
dostępnych od razu po zainstalowaniu R.
Funkcja ls()
pokazuje nam wszystkie
obiekty w środowisku pracy (workspace)
ls()
## [1] "analiza" "concat_wektorow"
## [3] "czestosc_orla" "dane"
## [5] "dane_lista" "dane_norm"
## [7] "dane_std" "df"
## [9] "dlugosci" "factor_sex_vector"
## [11] "factor_temperatura_vector" "factor_vector_plci"
## [13] "filozofia" "gosciu"
## [15] "gosciuwa" "id"
## [17] "id2" "imiona"
## [19] "imiona_posortowane" "imiona_posortowane_malejaco"
## [21] "imiona_sorted" "imiona_sorted_desc"
## [23] "imiona_studentow" "kierunek"
## [25] "kolejnosc_rosnaco" "kolor"
## [27] "kolory" "ksiazki"
## [29] "ksiazki_po_2010" "ksiazki_po_2010_alt"
## [31] "ksiazki_posortowane" "ksiazki_posortowane_alt"
## [33] "liczba_orlow" "liczba_reszek"
## [35] "liczby" "liczby_1_100"
## [37] "liczby_f" "liczby_lista"
## [39] "lista_bez_nazw" "losowe_liczby"
## [41] "macierz_przyklad" "matematyka"
## [43] "miesiace" "model"
## [45] "moja.zmienna" "moja_dokladna_liczba"
## [47] "moja_liczba" "moja_lista"
## [49] "moja_wart_logiczna" "moja_wart_logiczna2"
## [51] "moja_zmienna" "MojaKlasa"
## [53] "mojaZmienna" "moje_slowo"
## [55] "mtcars" "name_vector"
## [57] "nazwa_przedmiotu" "nowa_planeta"
## [59] "oceny" "oceny_matrix"
## [61] "oceny_matrix2" "oceny_odwrocone"
## [63] "oceny_stat_R" "oceny_text"
## [65] "osoba" "owoce"
## [67] "planets_df" "plec"
## [69] "podzielne_przez_7" "podzielne_przez_7_v2"
## [71] "polskie_nazwy_mtcars" "pozycja"
## [73] "przeczytane" "rings_vector"
## [75] "rzuty" "rzuty_moneta"
## [77] "rzuty_moneta2" "sekwencjaNumericow"
## [79] "sekwencjaNumericow2" "sekwencjaNumericow3"
## [81] "semestry" "sex_vector"
## [83] "sprzedaz" "srednia"
## [85] "srednia_ocen" "srednia_ocena_przeczytanych"
## [87] "srednia_semestr" "stat_R"
## [89] "suma_wektorow" "szesc"
## [91] "szpital" "tablica_przyklad"
## [93] "tekst" "temperatura"
## [95] "temperatura_vector" "trufolsy"
## [97] "vector_plci" "warunki"
## [99] "wektor" "wektor_1"
## [101] "wektor_2" "wektor_z_brakami"
## [103] "wiek" "wieksze_od_sredniej"
## [105] "wych_fiz" "wyniki"
## [107] "wysoka" "x"
## [109] "y" "z"
## [111] "za_co" "zdali"
Funkcja rm()
usuwa poszczególne obiekty
ze środowiska
rm(oceny_matrix)
Kombinacja powyższych funkcji czyści cały workspace
rm(list=ls())
Można to również “wyklikać” w RStudio, co za moment pokażę.
Gdyby nam zależało na pozostawieniu pojedynczych obiektów?
rm(list=setdiff(ls(), "oceny_stat_R"))
Funkcja gc()
w R jest
używana do zarządzania pamięcią poprzez przeprowadzanie tzw. garbage
collection (zbieranie śmieci). gc()
oczyszcza pamięć,
usuwając nieużywane obiekty, co może zwolnić zasoby systemowe. Po
wykonaniu, funkcja zwraca raport o aktualnym zużyciu pamięci, co może
być przydatne do monitorowania i optymalizacji kodu. Rekomenduje się
używać jej po usunięciu dużych obiektów ze środowiska (czasem już ich
nie widać, a zalegają nam gdzieś w RAMie).
gc()
## used (Mb) gc trigger (Mb) max used (Mb)
## Ncells 609957 32.6 1546431 82.6 1546431 82.6
## Vcells 1181930 9.1 8388608 64.0 6601446 50.4
Wtręt. Wyłączanie notacji naukowej (scientific notation)
# przykład notacji wykładniczej
5834617 * 10^5
## [1] 583461700000
# i naukowej
5.834617 * 10^5 == 5.834617e+5
## [1] TRUE
5.834617e+5 == 583461.7
## [1] TRUE
# jakieś random'owe liczby (Funkcja exp() w R służy do obliczania wartości wykładniczej liczby e (około 2.71828) podniesionej do potęgi podanego argumentu)
exp(-42) # super mała, w notacji naukowej
## [1] 5.749522e-19
exp(42) # super duża, w notacji naukowej
## [1] 1.739275e+18
# Jeśli uruchomimy
options(scipen = 15) # opcja systemowa scipen (scientific penalty)
# to wówczas w konsoli pojawią nam się inne wyświetlenia
exp(-42) # super mała, pozbawiona notacji
## [1] 0.0000000000000000005749522
exp(42) # super duża, analogicznie
## [1] 1739274941520500992
Wtręt. Zmniejszenie wyświetlania liczby znaków
Jeśli chcemy co do zasady w konsoli widzieć mniej znaków (i tym samym miejsc po przecinku), możemy osiągnąć to używając poniższej funkcji systemowe
pi # przykład obiektu, który istnieje bez naszej ingerencji, na podobnej zasadzie co np.`letters`
## [1] 3.141593
# albo nie istnieje ale stworzyliśmy
(e <- exp(1))
## [1] 2.718282
options(digits = 3) # zmieniamy opcje systemową
# wówczas
pi # znane nam "czyczternaście"
## [1] 3.14
# albo
e
## [1] 2.72
Funkcje floor(x)
i
ceiling(x)
zaokrąglają do najbliższej
wartości całkowitej odpowiednio w dół lub w górę. Poniżej przykłady.
floor(1.23456789)
## [1] 1
floor(-1.23456789)
## [1] -2
ceiling(1.23456789)
## [1] 2
ceiling(-1.23456789)
## [1] -1
Funkcja choose(n,x)
w R służy do
obliczania współczynnika dwumianowego, czyli liczby sposobów, w jakie
można wybrać (k
) elementów z (n
) elementów bez
uwzględniania kolejności.
# Liczba sposobów na wybranie 2 elementów z 5
choose(5, 2)
## [1] 10
# chcąc sprawdzić jakie to będą pary, można posłużyć się takim kodem
# Zbiór elementów
elements <- c(1, 2, 3, 4, 5) # pięć elementów
# Generowanie wszystkich kombinacji 2-elementowych
combinations <- combn(elements, 2)
print(combinations)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 1 1 1 1 2 2 2 3 3 4
## [2,] 2 3 4 5 3 4 5 4 5 5
Funkcja factorial()
w R służy do
obliczania silni liczby. Silnia liczby (n
) (oznaczana jako
(n!
)) to iloczyn wszystkich liczb całkowitych od 1 do
(n
).
# Obliczanie silni liczby 5
factorial(5)
## [1] 120
# tak nie, wykrzyknik służył do negacji
5!
Nie znając funkcji choose()
, a znając
factorial()
i wzory, można np. samemu policzyć…
# choose(n = 5, k = 2)
factorial(5) / (factorial(2) * factorial(5-2))
## [1] 10
Funkcja trunc()
w R służy do obcinania
części dziesiętnej liczby, czyli usuwania wszystkiego, co znajduje się
po przecinku, i zwracania liczby całkowitej najbliższej zeru. Na
przykład, liczba dodatnia zostanie zaokrąglona w dół, a liczba ujemna w
górę
# Obcinanie części dziesiętnej liczby dodatniej
trunc(pi)
## [1] 3
# Obcinanie części dziesiętnej liczby ujemnej
trunc(-e)
## [1] -2
Funkcja runif(n)
generuje
n losowych liczb z rozkładu jednostajnego (uniform
distribution). W rozkładzie jednostajnym każda wartość w określonym
przedziale ma jednakowe prawdopodobieństwo wystąpienia. Używana do
generowania pseudolosowych liczb w określonym przedziale, co jest
przydatne w symulacjach, testach statystycznych i innych analizach
wymagających losowych danych.
Składnia: runif(n, min = 0, max = 1)
* n
:
Liczba losowych wartości do wygenerowania. * min
: Minimalna
wartość przedziału (domyślnie 0). * max
: Maksymalna wartość
przedziału (domyślnie 1).
# Generowanie 1000 losowych liczb z przedziału 0 do 100
runif_result <- runif(10^3, min = 0, max = 100)
# rezultat
hist(runif_result)
Funkcja rnorm(n)
generuje
n losowych liczb z rozkładu normalnego (Gaussian
distribution). Rozkład normalny jest symetryczny i ma kształt
dzwonu (kapelusza, słonia w wężu), z wartościami skupionymi wokół
średniej. Używana do generowania pseudolosowych liczb, które mają
rozkład normalny, co jest przydatne w analizach statystycznych,
modelowaniu i symulacjach, gdzie dane często przyjmują rozkład
normalny.
Składnia: rnorm(n, mean = 0, sd = 1)
* n: Liczba
losowych wartości do wygenerowania. * mean: Średnia rozkładu (domyślnie
0). * sd: Odchylenie standardowe rozkładu (domyślnie 1).
# Generowanie 1000 losowych liczb z rozkładu normalnego o średniej 10 i odchyleniu standardowym 2
rnorm_result <- rnorm(1000, mean = 10, sd = 2)
# rezultat
hist(rnorm_result)
Do szybkiego stworzenia prostych statystyk opisowych możemy posłużyć się następującymi funkcjami:
max()
maksimummax(rnorm_result) # nasz pseudolosowy wektor z poprzedniego przykładu
## [1] 16.8
max(runif_result) # nasz pseudolosowy wektor z poprzedniego przykładu
## [1] 99.9
min()
minimummin(rnorm_result)
## [1] 4.61
min(runif_result)
## [1] 0.0465
sum()
sumasum(rnorm_result)
## [1] 10053
sum(runif_result)
## [1] 49524
mean()
średniamean(rnorm_result)
## [1] 10.1
mean(runif_result)
## [1] 49.5
median()
medianamedian(rnorm_result)
## [1] 10.1
median(runif_result)
## [1] 49.2
range()
liczy zakres wartości
vide minimum i maksimum.range(rnorm_result)
## [1] 4.61 16.78
range(runif_result)
## [1] 0.0465 99.9405
quantile()
służy do obliczania
kwantyli dla danego wektora danych.Kwantyle to wartości, które dzielą uporządkowany zbiór danych na równe części. Używane do opisu rozkładu danych, zrozumienia struktury danych, identyfikacji wartości odstających i porównywania różnych zbiorów danych.
Argumenty: * x
: Wektor danych, dla którego chcemy
obliczyć kwantyle. * probs
: Wektor wartości
prawdopodobieństwa, które określają, jakie kwantyle mają być obliczone
(domyślnie kwartyle: 0, 0.25, 0.5, 0.75, 1). * na.rm
: Jeśli
ustawione na TRUE, pomija wartości NA w obliczeniach (domyślnie
FALSE).
# domyślnie liczy kwartyle, gdy wywołujemy funkcję bez dodatkowych argumentów
quantile(rnorm_result)
## 0% 25% 50% 75% 100%
## 4.61 8.66 10.11 11.33 16.78
quantile(runif_result)
## 0% 25% 50% 75% 100%
## 0.0465 25.2519 49.2430 74.7835 99.9405
# można również percentyle
quantile(rnorm_result, probs = seq(0, 1, 0.1), na.rm = TRUE)
## 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
## 4.61 7.47 8.35 9.02 9.63 10.11 10.60 11.09 11.68 12.56 16.78
quantile(runif_result, probs = seq(0, 1, 0.1), na.rm = FALSE)
## 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%
## 0.0465 9.6167 19.3266 29.7297 39.5800 49.2430 58.7086 69.9259 79.8087 88.7452
## 100%
## 99.9405
sd()
w R służy do obliczania
odchylenia standardowego wektora danych.Odchylenie standardowe mierzy, jak bardzo wartości w zbiorze danych różnią się od średniej, ale w tych samych jednostkach co oryginalne dane.
(x <- c(1, 2, 3, 4, 5)) # wektor
## [1] 1 2 3 4 5
sd(x)
## [1] 1.58
sd(rnorm_result)
## [1] 2
sd(runif_result)
## [1] 28.8
var()
wariancjaWariancja mierzy średnią kwadratową odległość wartości w zbiorze danych od ich średniej. Jest to miara rozproszenia danych.
(x <- c(1, 2, 3, 4, 5)) # wektor
## [1] 1 2 3 4 5
var(x)
## [1] 2.5
sd(x)^2
## [1] 2.5
var(rnorm_result)
## [1] 4
var(runif_result)
## [1] 829
cumsum()
służy do obliczania
skumulowanej sumy elementów wektora. Oznacza to, że każdy element
wynikowego wektora jest sumą wszystkich poprzednich elementów
oryginalnego wektora do tego punktu włącznie.(x <- c(1, 2, 3, 4, 5)) # wektor
## [1] 1 2 3 4 5
cumsum(x) # skumulowana suma wektora
## [1] 1 3 6 10 15
cumprod()
służy do obliczania
skumulowanego iloczynu elementów wektora. Oznacza to, że każdy element
wynikowego wektora jest iloczynem wszystkich poprzednich elementów
oryginalnego wektora do tego punktu włącznie.x <- c(2, 3, 4, 5) # wektor
cumprod(x) # skumulowany iloczyn wektora
## [1] 2 6 24 120
cummax()
(x <- c(1, 2, 3, 4, 5)) # wektor
## [1] 1 2 3 4 5
cummax(x)
## [1] 1 2 3 4 5
cummin()
(x <- c(1, 2, 3, 4, 5)) # wektor
## [1] 1 2 3 4 5
cummin(x)
## [1] 1 1 1 1 1
Pytanie do Państwa, co zrobiły powyższe dwie funkcje? Widzicie Państwo jakieś zastosowanie wyników?
cor()
korelacjaFunkcja cor()
oblicza współczynnik korelacji między
dwoma wektorami danych. Korelacja mierzy siłę i kierunek związku między
dwiema zmiennymi. Składnia:
cor(x, y = NULL, use = "everything", method = c("pearson", "kendall", "spearman"))
* x
: Wektor numeryczny lub macierz. * y
:
Opcjonalnie, drugi wektor numeryczny (jeśli nie podano, używa x). *
use
: Metoda obsługi wartości NA. * method
:
Metoda korelacji (“pearson” domyślnie, “kendall”, “spearman”).
(x <- c(1, 2, 3, 4, 5)); (y <- 3*x)
## [1] 1 2 3 4 5
## [1] 3 6 9 12 15
cor(x, y)
## [1] 1
# idealnie!
cor(rnorm_result, runif_result)
## [1] 0.0385
# jakiś komentarz co do wyniku?
Dwie przydatne funkcje: sort()
&
order()
. Przydatne np. chcąc wyświetlić
posortowaną zmienną (kolumnę) w tabeli lub wymusić inne niż domyślne
rysowanie elementów na osiach wykresu.
# Stwórzmy szybko przykładowy wektor trójelementowy
(a <- c(100, 10, 1000))
## [1] 100 10 1000
order(a)
## [1] 2 1 3
sort(a)
## [1] 10 100 1000
a[order(a)] # można posortować wektor indeksując go funkcją order(), da taki sam rezultat jak sort()
## [1] 10 100 1000
a # w środku dotychczasowa kolejność
## [1] 100 10 1000
# chcąc mieć na stałe posortowany wektor musimy go sobie nadpisać
(a <- a[order(a)])
## [1] 10 100 1000
Można jeszcze skorzystać z funkcji
rank()
. w R służy do przypisywania rang
wartościom w wektorze. Jest to przydatne, gdy chcesz uporządkować dane
według ich wartości, ale zamiast sortować je bezpośrednio, przypisujesz
im rangi.
(a <- c(100, 10, 1000))
## [1] 100 10 1000
rank(a)
## [1] 2 1 3
Nieco bardziej skomplikowana sytuacja.
(a <- c(100, 10, 1000, 10, NA))
## [1] 100 10 1000 10 NA
rank(a)
## [1] 3.0 1.5 4.0 1.5 5.0
Wówczas warto sięgnąć po większą liczbę argumentów tej funkcji.
rank(x, na.last = TRUE, ties.method = c("average", "first", "last", "random", "max", "min"))
gdzie:
x
: Wektor numeryczny, złożony, znakowy lub logiczny,
którego rangi chcesz obliczyć.na.last
: Określa, jak traktować wartości NA. Może być
TRUE (domyślnie, NA na końcu), FALSE (NA na początku), NA (usuwa NA) lub
“keep” (zachowuje NA z rangą NA).ties.method
: Określa sposób traktowania remisów
(wartości równych). Opcje to:
"average"
: Przypisuje średnią rangę dla remisów
(domyślnie)."first"
: Przypisuje rangi według pierwszego
wystąpienia."last"
: Przypisuje rangi według ostatniego
wystąpienia."random"
: Przypisuje rangi losowo."max"
: Przypisuje maksymalną rangę dla remisów."min"
: Przypisuje minimalną rangę dla remisów.Funkcje paste()
i
cat()
w R służą do łączenia (konkatenacji)
ciągów znaków, ale mają różne zastosowania i zachowania.
Kluczowe różnice:
paste()
zwraca wartość, cat()
tylko
wyświetla wynikpaste()
domyślnie dodaje spację, cat()
nie
dodaje separatora, chyba że jest to określonePoniżej kilka przykładów użycia.
tekst <- paste("Ta książka Vonnegut'a to bodaj \"Kocia kołyska\"!"); tekst
## [1] "Ta książka Vonnegut'a to bodaj \"Kocia kołyska\"!"
cat(tekst) # nie ma znaków specjalnych, wyłączających inne znaki specjalne
## Ta książka Vonnegut'a to bodaj "Kocia kołyska"!
tekst2 <- paste('Ta książka Vonnegut\'a to bodaj \"Kocia kołyska\"!'); tekst # to samo co powyżej, ale zamiana cudzysłowu na apostrof
## [1] "Ta książka Vonnegut'a to bodaj \"Kocia kołyska\"!"
cat(tekst2)
## Ta książka Vonnegut'a to bodaj "Kocia kołyska"!
tekst==tekst2
## [1] TRUE
# można ręcznie łamać tekst (\n)
tekst3 <- paste("Ta książka Vonnegut'a to bodaj \n\"Kocia kołyska\"\n!"); tekst3
## [1] "Ta książka Vonnegut'a to bodaj \n\"Kocia kołyska\"\n!"
cat(tekst3) # cat() znów printuje ładny output (prof Bralczyk by mnie odstrzelił za te makaronizmy)
## Ta książka Vonnegut'a to bodaj
## "Kocia kołyska"
## !
# a można o tym zapomnieć i po prostu klikać Enter pisząc kod
tekst4 <- paste("Ta książka Vonnegut'a to bodaj
\"Kocia kołyska\"
!"); tekst4
## [1] "Ta książka Vonnegut'a to bodaj \n\"Kocia kołyska\"\n!"
cat(tekst4)
## Ta książka Vonnegut'a to bodaj
## "Kocia kołyska"
## !
tekst3 == tekst4
## [1] TRUE
# po prostu konkatenacja wytworzonych przed momentem wektorów
paste(tekst, tekst2, tekst3, tekst4)
## [1] "Ta książka Vonnegut'a to bodaj \"Kocia kołyska\"! Ta książka Vonnegut'a to bodaj \"Kocia kołyska\"! Ta książka Vonnegut'a to bodaj \n\"Kocia kołyska\"\n! Ta książka Vonnegut'a to bodaj \n\"Kocia kołyska\"\n!"
cat(tekst, tekst2, tekst3, tekst4)
## Ta książka Vonnegut'a to bodaj "Kocia kołyska"! Ta książka Vonnegut'a to bodaj "Kocia kołyska"! Ta książka Vonnegut'a to bodaj
## "Kocia kołyska"
## ! Ta książka Vonnegut'a to bodaj
## "Kocia kołyska"
## !
Sugerowałbym, z uwagi na bardziej eleganckie wyświetlenie napisów,
używać cat()
np. do wyświetlania komunikatów
użytkownikowi.
Dodatkowo, istnieje funkcja paste0()
, bliźniacza do
paste()
z nieco innymi domyślnymi argumentami. Potrafiliby
Państwo powiedzieć czym się różnią? Można sprawdzić empirycznie, można
użyć dokumentacji obu funkcji. Nie wpisujcie Państwo proszę frazy w
Google czy prompt jakiegoś modelu językowego, zróbcie to
oldschool’owo.
Bywa, że chcemy szybko podejrzeć zawartość ramki danych lub wektora.
Wiemy, że jest długi i print trwałby jakiś czas i zamazał
de facto obraz w konsoli. Wówczas możemy posłużyć się funkcjami
head(x,n)
oraz
tail(x,n)
. Pierwsza wyświetli tyle
pierwszych elementów ile podamy w argumencie n, druga
tyleż samo tyle że od końca.
Funkcje można dowolnie w sobie zagnieżdżać, co już w sumie po poprzednich przykładach dało się intuicyjnie wyczuć.
# przykład 1
exp(floor(42.345)) - exp(sum(20,20)+2)
## [1] 0
# przykład 2
abs(-round(123 * exp(sqrt(log(3 ** 2 - 1 + 3 ** (2 - 1) / 3, base = 2))), -1))
## [1] 730
Ogólnie warto zajrzeć w Tools -> Keybords Shortcuts Help (Alt + Shift + K)
Materiały z warsztatów Data Science w zastosowaniach biznesowych - Warsztaty z wykorzystaniem programu R Uniwersytet Warszawski, Wydział Nauk Ekonomicznych
DataCamp.com Introduction to R
Materiały dr Bartosza Maćkiewicza:
Biecek, Przemysław, “Przewodnik po pakiecie R” http://www.biecek.pl/R/ https://cran.r-project.org/doc/contrib/Biecek-R-basics.pdf
Gągolewski, Marek, “Programowanie w języku R”, “Deep R Programming”, etc. https://deepr.gagolewski.com/index.html
Crawley, Michael J. The R book. John Wiley & Sons, 2012 https://onlinelibrary.wiley.com/doi/book/10.1002/9781118448908
Kabacoff, Robert. R in action: data analysis and graphics with R. Manning Publications Co., 2015 https://www.cs.uni.edu/~jacobson/4772/week11/R_in_Action.pdf
Fox, John, Michael Friendly, and Sanford Weisberg. “Hypothesis tests for multivariate linear models using the car package.” R J 5.1 (2013) https://www.researchgate.net/publication/285736465_Hypothesis_Tests_for_Multivariate_Linear_Models_Using_the_car_Package
Hothorn, Torsten, et al. “Package ‘multcomp’.” Simultaneous inference in general parametric models. Project for Statistical Computing, Vienna, Austria (2016) https://cran.r-project.org/web/packages/multcomp/vignettes/generalsiminf.pdf
claude.ai
chatgpt.com