Operatory
Operatory arytmetyczne
x <- 4
y <- 2
# dodawanie
x + y
## [1] 6
# odejmowanie
x - y
## [1] 2
# mnożenie
x * y
## [1] 8
# dzielenie
x / y
## [1] 2
# modulus
x %% y
## [1] 0
# power
x ^ y
## [1] 16
Operatory logiczne
# równe?
x == y
## [1] FALSE
# nie równe?
x != y
## [1] TRUE
# większe od?
x > y
## [1] TRUE
# mniejsze od?
x < y
## [1] FALSE
# większe lub równe od?
x >= y
## [1] TRUE
# mniejsze lub równe od?
x <= y
## [1] FALSE
Operator OR | i operator AND & są przydatne, gdy mamy do czynienia z twierdzeniami logicznymi.
(x > y) | (y < x)
## [1] TRUE
(x > y) & (y < x)
## [1] TRUE
c(F,F,F,T,F,F) | c(F,F,F,F,F,F)
## [1] FALSE FALSE FALSE TRUE FALSE FALSE
Teraz istnieją również dwa warianty || i &&. Operatory te porównują elementy od lewej do prawej i zatrzymują się po pierwszym elemencie. Rozważmy ten sam przykład powyżej, zastępując | przez ||. Wynikiem jest jeden element, a nie wektor.
c(F,F,F,T,F,F) || c(F,F,F,F,F,F)
## Warning in c(F, F, F, T, F, F) || c(F, F, F, F, F, F): 'length(x) = 6 > 1' in
## coercion to 'logical(1)'
## Warning in c(F, F, F, T, F, F) || c(F, F, F, F, F, F): 'length(x) = 6 > 1' in
## coercion to 'logical(1)'
## [1] FALSE
Lepszą praktyką jest używanie any() i all() do oceny wektorów logicznych na pojedynczy logiczny.
# Czy któreś z nich jest TRUE?
any(c(F,F,F,T,F,F))
## [1] TRUE
# Czy wszystkie z nich są TRUE?
all(c(F,F,F,T,F,F))
## [1] FALSE
Znaki/łańcuchy mogą być przypisane do zmiennych w podobny sposób.
z <- "to"
z1 <- "tamto"
paste(z,z1)
## [1] "to tamto"
Funkcja paste() łączy ciągi znaków.
Nazwy zmiennych muszą być tak dobrane, aby nie kolidowały z istniejącymi zmiennymi/funkcjami. Na przykład należy unikać nazwy zmiennej c, ponieważ jest to istniejąca funkcja do konkatenacji obiektów R. Należy unikać nazwy zmiennej t, ponieważ jest to funkcja do transpozycji macierzy. Nazwy zmiennych nie mogą zaczynać się od liczby.
Operator fajki
Możesz użyć operatora pipe (%>%) w R, aby “spiąć” razem sekwencję operacji.
Operator ten jest najczęściej używany z pakietem dplyr w R do wykonywania sekwencji operacji na ramce danych.
Podstawowa składnia operatora fajki to:
dane %>%
zrób coś %>%
a potem zrób jeszcze coś %>%
a potem wylicz/narysuj...
Operator fajki po prostu przekazuje wyniki jednej operacji do następnej operacji pod nią.
Zaletą stosowania operatora fajki jest to, że czyni on kod niezwykle łatwym do odczytania.
Fajka podstawowa
Podstawową funkcją dostarczaną przez pakiet magrittr jest %>%, lub tak zwany operator “pipe”. Operator ten przekazuje wartość, lub wynik wyrażenia, do następnego wywołania funkcji/wyrażenia. Na przykład funkcja filtrująca dane może być zapisana jako:
filter(data, variable == numeric_value)
lub:
data %>% filter(variable == numeric_value)
Obie funkcje wykonują to samo zadanie i korzyść z użycia %>% może nie być od razu oczywista; jednakże, gdy chcemy wykonać wiele funkcji, jej zaleta staje się oczywista.
Na przykład, jeśli chcemy przefiltrować pewne dane, pogrupować je według kategorii, podsumować je, a następnie uporządkować podsumowane wyniki, możemy wypisać to na trzy różne sposoby.
Możemy na przykład zmienić kolumny w bazowym zbiorze danych “mtcars”:
# zmieniamy nazwy kolumn
mtcars %>%
head %>%
set_colnames(paste("Col", 1:11, sep = ""))
## Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9 Col10 Col11
## Mazda RX4 21.0 6 160 110 3.90 2.62 16.5 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.88 17.0 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.21 19.4 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
Fajki dodatkowe
magrittr oferuje również kilka alternatywnych operatorów pipe. Niektóre funkcje, jak np. funkcje wykreślania, powodują zakończenie łańcucha argumentów przesyłanych rurociągiem.
Operator tee (%T>%) pozwala kontynuować piping funkcji, które normalnie powodują zakończenie.
mtcars %>%
filter(carb > 1) %>%
extract(, 1:4) %>%
plot() %>%
summary()
## Length Class Mode
## 0 NULL NULL
W powyższym przykładzie normalna fajka kończy się funkcją plot() dając w efekcie NULL jako wyniki dla funkcji summary()
Wstawienie %T>% pozwala na wykreślanie i wykonywanie funkcji, które podążają za funkcją plotowania:
mtcars %>%
filter(carb > 1) %>%
extract(, 1:4) %T>%
plot() %>%
summary()
## mpg cyl disp hp
## Min. :10.4 Min. :4.00 Min. : 76 Min. : 52
## 1st Qu.:15.2 1st Qu.:6.00 1st Qu.:147 1st Qu.:110
## Median :17.8 Median :8.00 Median :276 Median :175
## Mean :18.6 Mean :6.64 Mean :258 Mean :164
## 3rd Qu.:21.0 3rd Qu.:8.00 3rd Qu.:351 3rd Qu.:205
## Max. :30.4 Max. :8.00 Max. :472 Max. :335
Operator przypisania złożonego %<>% jest używany do aktualizowania wartości poprzez najpierw wprowadzenie jej do jednego lub więcej wyrażeń, a następnie przypisanie wyniku.
Na przykład, powiedzmy, że chcesz przekształcić zmienną mpg w ramce danych mtcars na pomiar pierwiastka kwadratowego. Użycie %<>% spowoduje wykonanie funkcji po prawej stronie %<>% i zapisanie zmian, jakie te funkcje wykonują, do zmiennej lub ramki danych wywołanej po lewej stronie %<>%.
mtcars$mpg %<>% sqrt
head(mtcars)
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 4.58 6 160 110 3.90 2.62 16.5 0 1 4 4
## Mazda RX4 Wag 4.58 6 160 110 3.90 2.88 17.0 0 1 4 4
## Datsun 710 4.77 4 108 93 3.85 2.32 18.6 1 1 4 1
## Hornet 4 Drive 4.63 6 258 110 3.08 3.21 19.4 1 0 3 1
## Hornet Sportabout 4.32 8 360 175 3.15 3.44 17.0 0 0 3 2
## Valiant 4.25 6 225 105 2.76 3.46 20.2 1 0 3 1
Niektóre funkcje (np. lm, aggregate, cor) posiadają argument data, który pozwala na bezpośrednie użycie nazw wewnątrz danych jako części wywołania.
Operator ekspozycji (%$%) jest przydatny, gdy chcemy przekazać ramkę danych, która może zawierać wiele kolumn, do funkcji, która jest stosowana tylko do niektórych kolumn.
Na przykład, funkcja korelacji (cor) wymaga tylko argumentu x i y, więc jeśli przesyłasz dane mtcars do funkcji cor używając %>%, otrzymasz błąd, ponieważ cor nie wie, jak obsługiwać mtcars. Jednak użycie %$% pozwala ci powiedzieć “weź tę ramkę danych, a następnie wykonaj cor() na tych określonych kolumnach w mtcars.”
Błąd no nie? Użycie %$% pozwala na wybranie zmiennych:
mtcars %>%
subset(vs == 0) %$%
cor(mpg, wt)
## [1] -0.831
Inne operatory
- Oto kilka innych powszechnie używanych operatorów.
-
jest używany do generowania sekwencji.
1:10
## [1] 1 2 3 4 5 6 7 8 9 10
%in% jest operatorem zbioru.
“a” %in% c(“x”, “p”, “a”, “c”) sprawdza, czy a jest członkiem zbioru x,p,a,c.
"a" %in% c("x","p","a","c")
## [1] TRUE
Odwrotność również by działała, ale liczba zwróconych elemntów jest teraz inna.
c("x","p","a","c") %in% "a"
## [1] FALSE FALSE TRUE FALSE
:: jest używany do bezpośredniego dostępu do funkcji z określonego pakietu. Kiedy normalnie wywołujesz funkcję, powiedzmy sum(), R przeszukuje przestrzeń nazw i znajduje ją. W przypadku, gdy istnieje funkcja sum() z innego pakietu, ostatnio załadowany pakiet zastępuje poprzednią funkcję. W takich przypadkach lub aby być całkowicie pewnym, że używasz właściwej funkcji z właściwego pakietu, możesz użyć package::function() do wywołania funkcji. Na przykład; base::sum(). ::: jest używane do wywoływania funkcji z pakietu, które nie są “eksportowane”. Jest to rzadko używane.
%*% jest używane do mnożenia macierzy.
matrix(c(2,2,3,3),nrow=2) %*% matrix(c(4,2,5,3),nrow=2)
## [,1] [,2]
## [1,] 14 19
## [2,] 14 19
matrix(c(2,2,3,3),nrow=2) %*% c(6,6)
## [,1]
## [1,] 30
## [2,] 30
Operacje na datach
Operacje na datach i format daty nie są takie proste i oczywiste jak by się wydawało.
Proszę prześledź kilka poniższych przykładów operacji z datami.
x <- "2013-04-03"
# Jaka jest struktura x?
str(x)
## chr "2013-04-03"
# Użyj as.Date() aby zmienić format na datę
x_date <- as.Date(x)
str(x_date)
## Date[1:1], format: "2013-04-03"
# Zamień April 10 2014 jako datę
april_10_2014 <- as.Date("2014-04-10")
Użyjmy pakietu readr. Co wykonują poniższe czynności?
as.POSIXct("2010-10-01 12:12:00")
## [1] "2010-10-01 12:12:00 CEST"
as.POSIXct("2010-10-01 12:12:00", tz = "America/Los_Angeles")
## [1] "2010-10-01 12:12:00 PDT"
Bardzo przydatny jest pakiet “lubridate” dla operacji z datami.
library(lubridate)
x <- "2010 September 20th" # 2010-09-20
ymd(x)
## [1] "2010-09-20"
y <- "02.01.2010" # 2010-01-02
dmy(y)
## [1] "2010-01-02"
z <- "Sep, 12th 2010 14:00" # 2010-09-12T14:00
mdy_hm(z)
## [1] "2010-09-12 14:00:00 UTC"
Możemy także w dowolny sposób manipulować formatem wyświetlania dat.
# Kolejność:
x <- "Monday June 1st 2010 at 4pm"
parse_date_time(x, orders = "amdyIp")
## Warning: All formats failed to parse. No formats found.
## [1] NA
two_orders <- c("October 7, 2001", "October 13, 2002", "April 13, 2003", "17 April 2005", "23 April 2017")
parse_date_time(two_orders, orders = c("mdy","dmy"))
## [1] "2001-10-07 UTC" "2002-10-13 UTC" "2003-04-13 UTC" "2005-04-17 UTC"
## [5] "2017-04-23 UTC"
short_dates <- c("11 December 1282", "May 1372", "1253")
myorders <- c("dOmY", "OmY", "Y")
parse_date_time(short_dates, orders = myorders)
## [1] "1282-12-11 UTC" "1372-05-01 UTC" "1253-01-01 UTC"
Funkcje pakietu lubridate pozwalają nam również zaokrąglać formaty dat.
r_3_4_1 <- ymd_hms("2016-05-03 07:13:28 UTC")
# Zaokrąglij w dół do dni
floor_date(r_3_4_1, unit = "day")
## [1] "2016-05-03 UTC"
# Zaokrąglij do 5 minut
round_date(r_3_4_1, unit = "5 minutes")
## [1] "2016-05-03 07:15:00 UTC"
# Zaokrąglij do tygodni
ceiling_date(r_3_4_1, unit = "week")
## [1] "2016-05-08 UTC"
# Odejmij od r_3_4_1 ją samą i zaokrąglij do dni
r_3_4_1 - floor_date(r_3_4_1, unit = "day")
## Time difference of 7.22 hours
Rozpatrzmy funkcje obliczeniowe dat:
# Lądowanie na księżycu :)
date_landing <- mdy("July 20, 1969")
moment_step <- mdy_hms("July 20, 1969, 02:56:15", tz = "UTC")
# Ile dni już upłynęło??
difftime(today(), date_landing, units = "days")
## Time difference of 19474 days
# Ile sekund?
difftime(now(),moment_step, units = "secs")
## Time difference of 1682589141 secs
Możemy łatwo obliczać różnice między datami:
# 3 daty
mar_11 <- ymd_hms("2017-03-11 12:00:00",
tz = "America/Los_Angeles")
mar_12 <- ymd_hms("2017-03-12 12:00:00",
tz = "America/Los_Angeles")
mar_13 <- ymd_hms("2017-03-13 12:00:00",
tz = "America/Los_Angeles")
# Różnica pomiędzy mar_13 oraz mar_12 w sekundach
difftime(mar_13, mar_12, units = "secs")
## Time difference of 86400 secs
Możemy również manipulować datami, dodawać lub odejmować okresy:
# Dodaj jeden tydzień do mon_2pm
mon_2pm <- dmy_hm("27 Aug 2018 14:00")
mon_2pm + weeks(1)
## [1] "2018-09-03 14:00:00 UTC"
# Dodaj 81 godzin do tue_9am
tue_9am <- dmy_hm("28 Aug 2018 9:00")
tue_9am + dhours(81)
## [1] "2018-08-31 18:00:00 UTC"
# Odejmij 5 lat od today()
today() - years(5)
## [1] "2017-11-13"
# Odejmij 5 lat od today()
today() - dyears(5)
## [1] "2017-11-12 18:00:00 UTC"
Możemy również manipulować sekwencjami:
# Dodaj 8 godzin:
today_8am <- today() + hours(8)
# Sekwencja 1 do 26:
every_two_weeks <- 1:26 * weeks(2)
# Utwórz sekwencję dat co 2 tygodnie przez rok:
every_two_weeks + today_8am
## [1] "2022-11-27 08:00:00 UTC" "2022-12-11 08:00:00 UTC"
## [3] "2022-12-25 08:00:00 UTC" "2023-01-08 08:00:00 UTC"
## [5] "2023-01-22 08:00:00 UTC" "2023-02-05 08:00:00 UTC"
## [7] "2023-02-19 08:00:00 UTC" "2023-03-05 08:00:00 UTC"
## [9] "2023-03-19 08:00:00 UTC" "2023-04-02 08:00:00 UTC"
## [11] "2023-04-16 08:00:00 UTC" "2023-04-30 08:00:00 UTC"
## [13] "2023-05-14 08:00:00 UTC" "2023-05-28 08:00:00 UTC"
## [15] "2023-06-11 08:00:00 UTC" "2023-06-25 08:00:00 UTC"
## [17] "2023-07-09 08:00:00 UTC" "2023-07-23 08:00:00 UTC"
## [19] "2023-08-06 08:00:00 UTC" "2023-08-20 08:00:00 UTC"
## [21] "2023-09-03 08:00:00 UTC" "2023-09-17 08:00:00 UTC"
## [23] "2023-10-01 08:00:00 UTC" "2023-10-15 08:00:00 UTC"
## [25] "2023-10-29 08:00:00 UTC" "2023-11-12 08:00:00 UTC"
Funkcje
Funkcje, które są dostarczane z bazową instalacją R, są określane jako funkcje wbudowane lub funkcje bazowe.
R ma mnóstwo wbudowanych funkcji do różnych zastosowań, takich jak analiza danych, programowanie, matematyka, wykreślanie itp.
Dodatkowe funkcje mogą być udostępnione poprzez zainstalowanie zewnętrznych pakietów.
Funkcje podstawowe
Poniżej przedstawiono kilka funkcji, które można zastosować do danych liczbowych:
# wygeneruj 10 liczb losowych z zakresu od 1 do 200
x <- sample(x=1:200,10)
# długość
length(x)
## [1] 10
# suma
sum(x)
## [1] 1042
# średnia
mean(x)
## [1] 104
# mediana
median(x)
## [1] 120
# minimum
min(x)
## [1] 14
# logarytm
log(x)
## [1] 4.84 3.04 5.07 4.08 2.64 4.22 4.83 5.06 5.29 4.74
# exponent
exp(x)
## [1] 5261441182666385969260048002882000244028024606446624080
## [2] 1318815734
## [3] 1129334570280557030248604642448862088824286022446642028866486868642460
## [4] 42012104037905144312428240
## [5] 1202604
## [6] 340427604993174075820288262482
## [7] 1935576042035722587620684448060202088046604022084400486
## [8] 152838813937817464970822600008640446008048420604604048866680606280428
## [9] 97792920656963182648202266280880468064866688084260660886246086868468240246060444806864
## [10] 87875016358370231080888420042442426000022224468882
# pierwiastek
sqrt(x)
## [1] 11.22 4.58 12.61 7.68 3.74 8.25 11.18 12.53 14.07 10.72
# zaokrąglanie
#round()
#Domyślnie zaokrągla wartości do 0 miejsc po #przecinku. Wypróbuj ?round w konsoli dla odmian #round() i sposobów zmiany liczby cyfr do #zaokrąglenia.
Funkcje użytkowe
R posiada kilka funkcji do żonglowania strukturami danych:
seq(): Generuje sekwencje, określając argumenty from,
to, oraz by.
rep(): Replikuj elementy wektorów i list.
sort(): Sortuj wektor w porządku rosnącym. Działa na
liczbach, ale także na łańcuchach znaków i logikach.
rev(): Odwraca elementy w strukturach danych, dla
których zdefiniowano odwracanie.
str(): Wyświetl strukturę dowolnego obiektu R.
append(): Połącz wektory lub listy.
is.*(): Sprawdź klasę obiektu R.
as.*(): Konwertowanie obiektu R z jednej klasy na
inną.
unlist(): Spłaszcz (ewentualnie osadzone) listy, aby
uzyskać wektor.
Funkcje tekstowe
Kilka przydatnych funkcji związanych z ciągami znaków:
a <- "sunny"
b <- "day"
# połącz
paste(a, b)
## [1] "sunny day"
# odnajdź wzór
grep("sun", a)
## [1] 1
# liczba znaków
nchar("sunny")
## [1] 5
# do dużej litery
toupper("sunny")
## [1] "SUNNY"
# do małej litery
tolower("SUNNY")
## [1] "sunny"
# zamiana wzoru
sub("sun", "fun", "sunny")
## [1] "funny"
# podciąg
substr("sunny", start=1, stop=3)
## [1] "sun"
grepl & grep
W swojej najbardziej podstawowej formie, wyrażenia regularne mogą być użyte do sprawdzenia, czy dany wzorzec istnieje wewnątrz łańcucha znaków lub wektora łańcuchów znaków.
W tym celu można użyć:
grepl(), które zwraca TRUE, gdy wzorzec zostanie
znaleziony w odpowiednim łańcuchu znaków.
grep(), która zwraca wektor indeksów łańcuchów znaków
zawierających wzorzec.
Obie funkcje potrzebują wzorca i argumentu x, gdzie
wzorzec jest wyrażeniem regularnym, które chcesz dopasować, a argument
x jest wektorem znaków, z którego należy szukać
dopasowań.
W tym i następnych ćwiczeniach, będziemy manipulować wektorem znaków adresów e-mail!
Wektor emaili został już zdefiniowany, więc możesz od razu przystąpić do wykonywania instrukcji!
# Wektor maili został już zdefiniowany dla Ciebie:
emails <- c("john.doe@ivyleague.edu", "education@world.gov", "dalai.lama@peace.org",
"invalid.edu", "quant@bigdatacollege.edu", "cookie.monster@sesame.tv")
# Użyj grepl() aby dopasować dla "edu"
grepl(pattern = "edu", x = emails)
## [1] TRUE TRUE FALSE TRUE TRUE FALSE
# Użyj grep() aby dopasować dla "edu", zapisz wynik do hits
hits <- grep(pattern = "edu", x = emails)
# Podzestaw emaili używając hits
emails[hits]
## [1] "john.doe@ivyleague.edu" "education@world.gov"
## [3] "invalid.edu" "quant@bigdatacollege.edu"
Możesz użyć znaku starszeństwa, ^, i znaku dolara,
$, aby dopasować zawartość znajdującą się odpowiednio w
start oraz end ciągu tekstowego.
To może nas przybliżyć o krok do poprawnego wzorca dopasowującego
tylko adresy e-mail ".edu" z naszej listy e-maili.
Ale jest jeszcze więcej rzeczy, które można dodać, aby uczynić wzorzec bardziej solidnym:
@, ponieważ poprawny email musi zawierać znak at.
.*, który pasuje do dowolnego znaku (.) zero lub więcej
razy (*). Zarówno dot jak i asterisk są
metaznakami.
Można ich użyć do dopasowania dowolnego znaku pomiędzy znakiem at a częścią “.edu” adresu email.
Aby dopasować część “edu” adresu e-mail na końcu łańcucha, należy
użyć znaku dot i asterisk.
Część \\ ucieka od kropki: mówi R, że chcesz użyć . jako
rzeczywistego znaku.
# Wektor emaili został już zdefiniowany dla Ciebie
emails <- c("john.doe@ivyleague.edu", "education@world.gov", "dalai.lama@peace.org",
"invalid.edu", "quant@bigdatacollege.edu", "cookie.monster@sesame.tv")
# Użyj grepl() aby dopasować adresy .edu bardziej solidnie
grepl(pattern = "@.edu$", x = emails)
## [1] FALSE FALSE FALSE FALSE FALSE FALSE
# Użyj grep(), aby dopasować adresy .edu bardziej solidnie, zapisując wynik w hits
hits <- grep(pattern = "@.*edu$", x = emails)
# Podzestaw emaili używając hits
emails[hits]
## [1] "john.doe@ivyleague.edu" "quant@bigdatacollege.edu"
sub i gsub
Podczas gdy grep() i grepl() były używane
do prostego sprawdzenia, czy wyrażenie regularne może być dopasowane do
wektora znaków, sub() i gsub() idą o krok
dalej: można podać argument zamiany. Jeśli wewnątrz wektora znaków x,
wzór wyrażenia regularnego zostanie znaleziony, pasujące elementy
zostaną zastąpione replacement.sub() zastępuje tylko
pierwsze dopasowanie, podczas gdy gsub() zastępuje
wszystkie dopasowania.
# Wektor emails został już zdefiniowany dla Ciebie
emails <- c("john.doe@ivyleague.edu", "education@world.gov", "global@peace.org",
"invalid.edu", "quant@bigdatacollege.edu", "cookie.monster@sesame.tv")
# Użyj sub() aby przekonwertować domeny email na pg.edu.pl
sub(pattern = "@*.edu$", replacement = "@pg.edu.pl", x = emails)
## [1] "john.doe@ivyleague@pg.edu.pl" "education@world.gov"
## [3] "global@peace.org" "invalid@pg.edu.pl"
## [5] "quant@bigdatacollege@pg.edu.pl" "cookie.monster@sesame.tv"
emails
## [1] "john.doe@ivyleague.edu" "education@world.gov"
## [3] "global@peace.org" "invalid.edu"
## [5] "quant@bigdatacollege.edu" "cookie.monster@sesame.tv"
# Dlaczego nie wymieniono wszystkich adresów??? ;-)
Wyrażenia regularne to typowa koncepcja, której nauczysz się poprzez działanie i oglądanie innych przykładów. Zanim zaczniesz się zastanawiać nad wyrażeniem regularnym w tym ćwiczeniu, spójrz na nowe rzeczy, które zostaną użyte:
.*: Zwykły podejrzany! Można go odczytać jako “każdy
znak, który jest dopasowany zero lub więcej razy”.
\\s: Dopasowanie spacji. S jest normalnie znakiem,
ucieczka od niego (\\) czyni go metaznakiem.
[0-9]+: Dopasuj liczby od 0 do 9, przynajmniej raz
(+).
([0-9]+): Nawiasy służą do udostępnienia części
pasującego łańcucha do zdefiniowania zastępstwa. Nawias w argumencie
replacement z sub() zostaje ustawiony na łańcuch, który jest
przechwytywany przez wyrażenie regularne [0-9]+.
awards <- c("Won 1 Oscar.",
"Won 1 Oscar. Another 9 wins & 24 nominations.",
"1 win and 2 nominations.",
"2 wins & 3 nominations.",
"Nominated for 2 Golden Globes. 1 more win & 2 nominations.",
"4 wins & 1 nomination.")
# Co zwraca ten fragment kodu?
sub(".*\\s([0-9]+)\\snomination.*$", "\\1", awards)
## [1] "Won 1 Oscar." "24" "2" "3" "2"
## [6] "1"
Czy możesz wyjaśnić, dlaczego co się dokładnie stało?
Otóż ([0-9]+) wybiera całą liczbę, która znajduje się
przed słowem “nominacje” w ciągu, a całe dopasowanie zostaje zastąpione
tą liczbą ze względu na odniesienie do treści wewnątrz nawiasów.
Funkcje ogólne
Kilka ogólnych funkcji:
print("hello")
## [1] "hello"
print("world")
## [1] "world"
cat("hello")
## hello
cat(" world")
## world
cat("\nhello\nworld")
##
## hello
## world
Jeśli widzisz, że kopiujesz fragment kodu R wiele razy, to prawdopodobnie dobrym pomysłem jest stworzenie z niego funkcji.
Załóżmy, że masz dwa wektory, na których chciałbyś wykonać serię operacji, a następnie wyprowadzić wynik.
a <- 1:6
b <- 8:10
d <- a*b
e <- log(d)
f <- sqrt(e)
f
## [1] 1.44 1.70 1.84 1.86 1.95 2.02
Możesz zmodyfikować ten blok kodu w funkcję w następujący sposób:
my_function <- function(a, b){
d <- a*b
e <- log(d)
f <- sqrt(e)
return(f)
}
Po zdefiniowaniu możesz użyć tego, gdziekolwiek jest to potrzebne:
my_function(a=2:4, b=6:8)
## [1] 1.58 1.74 1.86
Zmienne zdefiniowane wewnątrz funkcji są dostępne tylko wewnątrz tej funkcji i nie są dostępne poza nią, chyba że zostaną zwrócone:
W powyższej funkcji zmienna varz utworzona wewnątrz funkcji nie jest dostępna poza nią.
Możliwa jest jednak sytuacja odwrotna:
my_new_function <- function() {
varz <- foo + 2
return(varz)
}
foo <- 55
my_new_function()
## [1] 57
W powyższym przykładzie zmienna foo użyta wewnątrz funkcji nie jest dostarczona do funkcji poprzez argument, a mimo to udaje się ją znaleźć. Gdy funkcja nie znajduje zmiennej wewnątrz funkcji, szuka jej poza nią.
Funkcje warunkowe
Instrukcje warunkowe pisze się za pomocą if().
a <- 2
b <- 5
if(a < b) print(paste(a,"jest mniejsze od",b))
## [1] "2 jest mniejsze od 5"
else służy do dodania alternatywnego wyjścia:
a <- 2
b <- 5
if(a < b) {
print(paste(a,"jest mniejsze od",b))
}else{
print(paste(b,"jest mniejsze od",a))
}
## [1] "2 jest mniejsze od 5"
a <- 60
b <- 10
if(a < b) {
print(paste(a,"jest mniejsze od",b))
}else{
print(paste(b,"jest mniejsze od",a))
}
## [1] "10 jest mniejsze od 60"
instrukcje if else mogą być łączone w łańcuchy:
grade <- "B"
if(grade == "A"){
print("Ocena jest bardzo dobra!")
}else if(grade == "B"){
print("Ocena jest dobra.")
} else if (grade == "C") {
print("Ocena dostateczna.")
}
## [1] "Ocena jest dobra."
Nie należy tego mylić z funkcją o nazwie ifelse(). Jest ona również używana do wyboru warunkowego i przyjmuje postać ifelse(test, return-if-yes, return-if-no), a to jest wektorowe. Tak więc, na przykład, oto kilka wieków osób. Sklasyfikuj je jako dorosłych lub młodocianych.
x <- c(6,23,12,10,56,44)
ifelse(x>18,"Dorosły", "Młodociany")
## [1] "Młodociany" "Dorosły" "Młodociany" "Młodociany" "Dorosły"
## [6] "Dorosły"
Pętla for() jest przydatna do wielokrotnego uruchamiania poleceń przez znaną liczbę iteracji.
for (i in 1:5){
print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
Pętla while() jest przydatna do wielokrotnego uruchamiania poleceń przez nieznaną liczbę iteracji, aż do spełnienia jakiegoś warunku.
i <- 1
while(i < 5){
print(i)
i <- i+1
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
Struktura tibble
W całej tej książce pracujemy z “tibbles” zamiast tradycyjnego data.frame w R. Tibbles są ramkami danych, ale poprawiają niektóre starsze zachowania, aby ułatwić życie. R jest starym językiem i niektóre rzeczy, które były przydatne 10 lub 20 lat temu, teraz stają na drodze.
Trudno jest zmienić bazę R bez łamania istniejącego kodu, więc większość innowacji pojawia się w pakietach. Tutaj zobaczmy jak działa tibble, który zapewnia opinane ramki danych, które sprawiają, że praca w tidyverse jest nieco łatwiejsza. W większości analiz używa się terminu tibble i data frame zamiennie.
tibble(
x = 1:5,
y = 1,
z = x ^ 2 + y
)
## # A tibble: 5 × 3
## x y z
## <int> <dbl> <dbl>
## 1 1 1 2
## 2 2 1 5
## 3 3 1 10
## 4 4 1 17
## 5 5 1 26
Jeśli jesteś już zaznajomiony z data.frame(), zauważ, że tibble() robi znacznie mniej: nigdy nie zmienia typu danych wejściowych (np. nigdy nie konwertuje ciągów znaków na współczynniki!), nigdy nie zmienia nazw zmiennych i nie tworzy nazw wierszy.
Główne różnice między tibble a ramką danych:
Tibble mają wyrafinowaną metodę drukowania, która pokazuje tylko pierwsze 10 wierszy i wszystkie kolumny, które mieszczą się na ekranie. To znacznie ułatwia pracę z dużymi danymi. Oprócz nazwy, każda kolumna podaje swój typ, co jest miłą cechą zapożyczoną z str()
Tibbles są zaprojektowane tak, abyś przypadkowo nie przytłoczył swojej konsoli, gdy drukujesz duże ramki danych. Ale czasami potrzebujesz więcej danych wyjściowych niż domyślny wyświetlacz. Istnieje kilka opcji, które mogą pomóc.
Zadanie do wykonania
Zadanie wykonaj w kilku etapach:
- Zapisz “dane” jako obiekt tibble pod inną nazwą, np. dane2. Porównaj je.
- Które ze zmiennych przekształcone powinny być w czynnik (factor)?
- Cena nieruchomości (price) jest obecnie integer. Czy to odpowiednie?
- Napisz własną funkcję, która wykonywać będzie standaryzowanie zmiennych.
- Utwórz nową zmienną “cena” w tibble “dane2”, która będzie zestandaryzowaną price, korzystając z własnej funkcji.
- Wykreśl cenę oraz price na wykresach ramkowych obok siebie na jednym ekranie. Różnice?
1.
## [1] 1
dane2 <- tibble(dane)
str(dane2)
## tibble [985 × 12] (S3: tbl_df/tbl/data.frame)
## $ street : chr [1:985] "3526 HIGH ST" "51 OMAHA CT" "2796 BRANCH ST" "2805 JANETTE WAY" ...
## $ city : chr [1:985] "SACRAMENTO" "SACRAMENTO" "SACRAMENTO" "SACRAMENTO" ...
## $ zip : int [1:985] 95838 95823 95815 95815 95824 95841 95842 95820 95670 95673 ...
## $ state : chr [1:985] "CA" "CA" "CA" "CA" ...
## $ beds : int [1:985] 2 3 2 2 2 3 3 3 2 3 ...
## $ baths : int [1:985] 1 1 1 1 1 1 2 1 2 2 ...
## $ sq__ft : int [1:985] 836 1167 796 852 797 1122 1104 1177 941 1146 ...
## $ type : chr [1:985] "Residential" "Residential" "Residential" "Residential" ...
## $ sale_date: chr [1:985] "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" ...
## $ price : int [1:985] 59222 68212 68880 69307 81900 89921 90895 91002 94905 98937 ...
## $ latitude : num [1:985] 38.6 38.5 38.6 38.6 38.5 ...
## $ longitude: num [1:985] -121 -121 -121 -121 -121 ...
str(dane)
## 'data.frame': 985 obs. of 12 variables:
## $ street : chr "3526 HIGH ST" "51 OMAHA CT" "2796 BRANCH ST" "2805 JANETTE WAY" ...
## $ city : chr "SACRAMENTO" "SACRAMENTO" "SACRAMENTO" "SACRAMENTO" ...
## $ zip : int 95838 95823 95815 95815 95824 95841 95842 95820 95670 95673 ...
## $ state : chr "CA" "CA" "CA" "CA" ...
## $ beds : int 2 3 2 2 2 3 3 3 2 3 ...
## $ baths : int 1 1 1 1 1 1 2 1 2 2 ...
## $ sq__ft : int 836 1167 796 852 797 1122 1104 1177 941 1146 ...
## $ type : chr "Residential" "Residential" "Residential" "Residential" ...
## $ sale_date: chr "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" ...
## $ price : int 59222 68212 68880 69307 81900 89921 90895 91002 94905 98937 ...
## $ latitude : num 38.6 38.5 38.6 38.6 38.5 ...
## $ longitude: num -121 -121 -121 -121 -121 ...
2. #te, które nadają się do grupowania danych
## [1] 2
city_factor = factor(dane2$city)
levels(city_factor)
## [1] "ANTELOPE" "AUBURN" "CAMERON PARK" "CARMICHAEL"
## [5] "CITRUS HEIGHTS" "COOL" "DIAMOND SPRINGS" "EL DORADO"
## [9] "EL DORADO HILLS" "ELK GROVE" "ELVERTA" "FAIR OAKS"
## [13] "FOLSOM" "FORESTHILL" "GALT" "GARDEN VALLEY"
## [17] "GOLD RIVER" "GRANITE BAY" "GREENWOOD" "LINCOLN"
## [21] "LOOMIS" "MATHER" "MEADOW VISTA" "NORTH HIGHLANDS"
## [25] "ORANGEVALE" "PENRYN" "PLACERVILLE" "POLLOCK PINES"
## [29] "RANCHO CORDOVA" "RANCHO MURIETA" "RIO LINDA" "ROCKLIN"
## [33] "ROSEVILLE" "SACRAMENTO" "SHINGLE SPRINGS" "SLOUGHHOUSE"
## [37] "WALNUT GROVE" "WEST SACRAMENTO" "WILTON"
type_factor = factor(dane2$type)
levels(type_factor)
## [1] "Condo" "Multi-Family" "Residential" "Unkown"
3. #format integer jest odpowiedni, chociaż posida ograniczenia co do przechowywania wartości. Można również spróbować zmienić format na numeric
## [1] 3
typeof(dane2$price)
## [1] "integer"
as.numeric(dane2$price)
## [1] 59222 68212 68880 69307 81900 89921 90895 91002 94905 98937
## [11] 100309 106250 106852 107502 108750 110700 113263 116250 120000 121630
## [21] 122000 122682 123000 124100 125000 126640 127281 129000 131200 132000
## [31] 133000 134555 136500 138750 141000 146250 147308 148750 149593 150000
## [41] 152000 154000 156896 161250 161500 164000 165000 166357 166357 168000
## [51] 170000 173000 174250 174313 178480 178760 179580 181000 181872 182587
## [61] 182716 182750 183200 188741 189000 192067 194000 194818 195000 198000
## [71] 199500 200000 200000 206000 208000 212864 221000 221000 223058 227887
## [81] 231477 234697 235000 236000 236685 237800 240122 242638 244000 244500
## [91] 244960 245918 250000 250000 250134 254200 254200 258000 260000 260014
## [101] 263500 265000 265000 271742 273750 275086 280908 280987 282400 285000
## [111] 287417 291000 292024 297000 297000 298000 299000 304037 311000 315537
## [121] 320000 320000 328360 334150 335750 335750 339500 344250 346210 347029
## [131] 347650 351300 352000 370000 370500 372000 375000 381300 381942 387731
## [141] 391000 394470 395000 400186 415000 425000 430000 445000 460000 461000
## [151] 489332 510000 539000 585000 600000 606238 660000 830000 69000 70000
## [161] 71000 78000 78400 80000 89000 90000 90000 92000 93675 97750
## [171] 98000 98000 99000 100000 106716 111000 111000 114800 120108 123225
## [181] 123750 125000 125000 126000 129000 134000 135000 135500 140000 140000
## [191] 142500 143500 145000 145000 145000 145000 146000 148500 149000 150000
## [201] 150000 152000 156000 156000 156000 157788 161653 161829 165000 168000
## [211] 169000 175000 176250 179000 180000 180400 182000 184500 185000 189000
## [221] 194000 195000 200000 201000 202500 205000 205000 205000 205000 207000
## [231] 210000 211500 215000 215000 215500 222381 225000 225000 225000 225000
## [241] 228000 229665 230000 230000 230000 234000 235000 236250 240000 242000
## [251] 245000 245000 245000 250000 250000 250000 250000 255000 256054 257729
## [261] 260000 261000 261800 264469 265000 270000 270000 270000 270000 275000
## [271] 275000 280000 286013 292000 292000 293993 294000 296769 297500 300000
## [281] 300000 300000 300000 300500 305000 306500 312500 315000 319789 330000
## [291] 330000 331000 334000 336000 339000 339000 345000 350000 356000 361745
## [301] 361948 370000 380000 385000 399000 402000 406026 420000 425000 425000
## [311] 433500 436746 438700 445000 450000 460000 460000 460000 465000 471750
## [321] 480000 484000 485000 495000 500500 504000 541000 560000 572500 582000
## [331] 613401 614000 680000 699000 839000 40000 48000 61500 62050 65000
## [341] 65000 68000 68000 77000 82732 84000 84675 85000 90000 90000
## [351] 91000 95000 97500 100000 100000 101000 102750 112500 113000 114000
## [361] 114000 114750 115000 115000 116100 119250 120000 120000 120000 120108
## [371] 121500 121725 122000 123000 125000 125573 126714 126960 127000 127500
## [381] 130000 133105 136500 139500 140000 140800 145000 147000 149600 150000
## [391] 150000 150000 155000 155435 155500 158000 158000 160000 160000 164000
## [401] 164000 165000 167000 167293 167293 168000 170000 170000 170000 174000
## [411] 178000 180000 180000 180000 182000 188325 191500 192000 192700 195000
## [421] 197654 198000 200345 203000 207000 208000 210000 212000 213675 213697
## [431] 215000 215000 215100 217500 218000 220000 221000 222900 223139 225500
## [441] 228327 230000 230000 230522 231200 232000 232500 233641 234000 234500
## [451] 235000 236000 236073 238000 238861 239700 240000 240000 241000 245000
## [461] 246000 247234 247480 249862 251000 252155 254172 258000 260000 261000
## [471] 261000 261000 262500 266000 266000 270000 274425 274500 275336 277980
## [481] 280000 284686 284893 285000 285000 285000 289000 295000 296000 296056
## [491] 297359 299940 304000 305000 307000 311328 313138 316630 320000 320000
## [501] 325000 328578 331000 331500 340000 344755 345746 351000 353767 355000
## [511] 356035 360000 360552 362305 365000 367554 368500 370000 371086 378000
## [521] 383000 388000 395100 400000 400000 408431 413000 416767 420000 423000
## [531] 423000 427500 430922 445000 450000 452000 470000 471000 475000 484500
## [541] 487500 488750 500000 506688 512000 520000 528000 579093 636000 668365
## [551] 676200 677048 691659 760000 4897 4897 4897 4897 4897 4897
## [561] 4897 4897 4897 4897 4897 4897 4897 4897 4897 4897
## [571] 4897 4897 4897 4897 4897 4897 4897 4897 4897 4897
## [581] 4897 4897 4897 4897 4897 4897 4897 4897 4897 4897
## [591] 4897 4897 4897 4897 4897 4897 4897 4897 4897 4897
## [601] 4897 4897 4897 30000 30000 55422 63000 65000 65000 65000
## [611] 66500 71000 75000 77000 85000 95625 96140 104250 105000 108000
## [621] 109000 115000 115000 115500 115620 116000 122000 122500 123000 124000
## [631] 124000 124413 125000 130000 131750 137721 137760 138000 140000 145000
## [641] 145000 150000 150000 151000 155000 155800 156142 158000 159900 160000
## [651] 161500 161600 162000 165000 165000 167293 168000 168000 168750 168750
## [661] 170000 170250 173000 175000 176095 176250 178000 179000 180000 180000
## [671] 180000 181000 182000 182587 185074 185833 186785 187000 188335 190000
## [681] 190000 190000 190000 191250 193000 193500 194818 195000 195000 195000
## [691] 195000 198000 199900 200000 201000 204918 205000 205000 205878 207000
## [701] 207744 209000 210000 210944 212500 213750 215000 215000 215000 216033
## [711] 220000 220000 220000 220000 220000 220702 221250 222000 222500 222750
## [721] 225000 225000 228750 229000 230095 232500 233000 233500 239000 240000
## [731] 240000 240971 242000 243450 243500 246544 246750 247000 247000 249000
## [741] 249000 250000 250000 250000 252000 255000 255000 255000 257200 260000
## [751] 260000 263500 266510 267750 270000 271000 272700 275000 275000 276000
## [761] 276500 278000 279000 280000 280000 285000 288000 289000 290000 290000
## [771] 293996 294000 294173 295000 298000 298000 299000 300000 300000 300000
## [781] 300567 303000 305000 306000 310000 310000 310000 311518 312000 313000
## [791] 315000 315000 315000 315000 315000 320000 322000 325000 325500 326951
## [801] 328370 330000 330000 331200 332000 334000 335000 341000 346375 347225
## [811] 349000 350000 350000 350000 350000 351000 356200 360000 367463 375000
## [821] 380000 380578 386222 389000 390000 395500 396000 397000 400000 400000
## [831] 412500 413500 415000 420454 425000 425000 433500 438000 441000 445000
## [841] 446000 450000 455000 460000 475000 490000 493000 508000 511000 525000
## [851] 533000 545000 560000 575000 575000 598695 600000 600000 600000 600000
## [861] 610000 622500 680000 879000 884790 1551 2000 56950 60000 61000
## [871] 62000 68566 70000 80000 85500 92000 93600 95000 97750 104000
## [881] 105000 107666 109000 110000 110000 112500 114800 116000 119000 121500
## [891] 122000 123675 126854 127059 128687 129500 130000 131750 132000 134000
## [901] 134000 138000 142000 143012 145846 147000 148750 150000 150454 151087
## [911] 157296 157500 160000 160000 161250 164000 165000 165000 165750 166000
## [921] 169000 170000 170000 170000 170000 170725 171750 172000 173056 174000
## [931] 174250 176850 179500 185000 188000 188700 189000 189000 189836 190000
## [941] 191250 191675 195500 198000 200000 200000 200000 200100 201528 204750
## [951] 205000 205000 205900 207000 207973 208250 208318 209347 211500 212000
## [961] 213000 216000 216021 219000 219794 220000 220000 220000 220000 223000
## [971] 224000 224000 224252 224500 225000 228000 229027 229500 230000 230000
## [981] 232425 234000 235000 235301 235738
4.
## [1] 4
mfunkcja <- function(x){
y<-(x-mean(x))/sd(x)
return(x)
}
5.
## [1] 5
cena <- mfunkcja(dane2$price)
dane2$cena <- mfunkcja(dane2$price)
str(dane2)
## tibble [985 × 13] (S3: tbl_df/tbl/data.frame)
## $ street : chr [1:985] "3526 HIGH ST" "51 OMAHA CT" "2796 BRANCH ST" "2805 JANETTE WAY" ...
## $ city : chr [1:985] "SACRAMENTO" "SACRAMENTO" "SACRAMENTO" "SACRAMENTO" ...
## $ zip : int [1:985] 95838 95823 95815 95815 95824 95841 95842 95820 95670 95673 ...
## $ state : chr [1:985] "CA" "CA" "CA" "CA" ...
## $ beds : int [1:985] 2 3 2 2 2 3 3 3 2 3 ...
## $ baths : int [1:985] 1 1 1 1 1 1 2 1 2 2 ...
## $ sq__ft : int [1:985] 836 1167 796 852 797 1122 1104 1177 941 1146 ...
## $ type : chr [1:985] "Residential" "Residential" "Residential" "Residential" ...
## $ sale_date: chr [1:985] "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" "Wed May 21 00:00:00 EDT 2008" ...
## $ price : int [1:985] 59222 68212 68880 69307 81900 89921 90895 91002 94905 98937 ...
## $ latitude : num [1:985] 38.6 38.5 38.6 38.6 38.5 ...
## $ longitude: num [1:985] -121 -121 -121 -121 -121 ...
## $ cena : int [1:985] 59222 68212 68880 69307 81900 89921 90895 91002 94905 98937 ...
6.
## [1] 6
par(mfrow=c(1,2))
boxplot(dane2$cena, main= "Cena-standaryzowanie", col= "grey")
boxplot(dane2$price, main= "Price", col= "yellow")