Obsah
1. Funkce v programovacím jazyku R
2. Funkce bez návratové hodnoty, speciální nehodnota NULL
3. Návratová hodnota funkce, konstrukce return
4. Pojmenované parametry volaných funkcí
5. Nepovinné parametry s výchozí hodnotou
7. Zavolání funkce pro všechny prvky seznamů nebo vektorů
8. Kombinace anonymní funkce a funkcí vyššího řádu sapply či lapply
10. Přístup k nelokálním proměnným
12. Klasický příklad uzávěru – čítač (generátor sekvence)
13. Čítač s předem nastaveným krokem
15. Funkce vyššího řádu v programovacím jazyce R
18. Balíčky s alternativní formou definice funkcí
19. Repositář s demonstračními příklady
1. Funkce v programovacím jazyku R
Jak jsme si již řekli v perexu článku, představují funkce v oblasti syntaxe a sémantiky programovacích jazyků jednu z nejužitečnějších abstrakcí vůbec. Pokud nějaký jazyk podporuje funkce (ideálně jako plnohodnotný datový typ), je možné programy strukturovat, izolovat čistě výpočetní části od částí, které mění stav aplikace atd. Některé programovací jazyky navíc díky podpoře lexikálních uzávěrů (closure) umožňují tvorbu generátorů atd. V programovacím jazyku R jsou funkce plnohodnotným datovým typem, což mj. znamená možnost využití funkcí vyšších řádů (higher order functions). Funkce navíc mohou modifikovat proměnné, které se nachází mimo oblast viditelnosti funkce, což se nejvíce využije právě při práci s uzávěry (pro modifikaci těchto proměnných se používá speciální operátor a nikoli například obdoba global či nonlocal z Pythonu).
Konstrukce funkcí je pochopitelně popsána přímo ve vestavěné nápovědě programovacího jazyka R:
help("function") function package:base R Documentation Function Definition Description: These functions provide the base mechanisms for defining new functions in the R language. Usage: function( arglist ) expr return(value) Arguments: arglist: Empty or one or more name or name=expression terms. expr: An expression. value: An expression.
2. Funkce bez návratové hodnoty, speciální nehodnota NULL
Nejjednodušší funkcí vůbec (a asi i nejméně užitečnou funkcí) je funkce, která neakceptuje žádné parametry, nevrací žádnou hodnotu a má prázdné tělo. Takovou funkci je možné v programovacím jazyku R zapsat následujícím způsobem:
f0 <- function() { }
Pokud tuto funkci zavoláme, vrátí se speciální nehodnota NULL:
> f0() NULL
Ve skutečnosti jsme NULL ještě nikdy v jazyku R nepoužili. Známe pouze speciální hodnoty NA a NaN (což jsou skutečné hodnoty se specifickým významem). NULL je ovšem poněkud odlišná v tom, že se skutečně jedná o „nic“, což se projeví například i při provádění relačních operací později v této kapitole. Pochopitelně se můžeme podívat do nápovědy:
> help(NULL)
Popis:
NULL package:base R Documentation The Null Object Description: ‘NULL’ represents the null object in R: it is a reserved word. ‘NULL’ is often returned by expressions and functions whose value is undefined. Usage: NULL as.null(x, ...) is.null(x) Arguments: x: an object to be tested or coerced. ...: ignored.
Lepší ovšem bude si způsoby práce s NULL vyzkoušet sami. Nejprve predikát is.null:
x <- NULL is.null(x) TRUE
Některé další predikáty vrací pro NULL hodnotu FALSE, takže se zdánlivě NULL příliš neliší od již zmíněných NA či NaN:
> is.numeric(x) [1] FALSE
Ve skutečnosti tomu tak však vždy není. Relační operátory, které by měly vracet TRUE či FALSE totiž pro NULL na vstupu vrátí prázdný vektor typu logical:
> x == 1 logical(0) > x == x logical(0) > x != x logical(0) > x < x logical(0) > x > x logical(0)
V praxi tedy prakticky vždy, když očekáváme, že by mohla nějaká proměnná obsahovat NULL, musíme použít predikát is.null a nikoli například x != NULL.
3. Návratová hodnota funkce, konstrukce return
Z funkce se automaticky vrací hodnota posledního výrazu. To například znamená, že funkce vracející konstantu může vypadat následovně:
f1 <- function() { 42 }
Otestujeme si chování takové funkce. Pokud si necháme vyhodnotit jen vlastní proměnnou s funkcí, vrátí se její zdrojový kód (což je docela užitečné):
> f1 function() { 42 }
Pokud funkci budeme chtít zavolat, je nutné použít kulaté závorky, i když se jedná o funkci bez parametrů:
> f1() [1] 42
Podobným způsobem můžeme vytvořit funkci se dvěma parametry, která vrací součet těchto parametrů:
add <- function(x, y) { x+y }
Otestování na dvou celých číslech:
> add(1,2) [1] 3
Parametry nemají uvedeny typ, takže můžeme použít například i komplexní čísla:
> add(1+2i, 3+4i) [1] 4+6i
Ovšem například pro řetězce dojde k chybě, neboť pro ně není operátor + definován:
> add("a","b") Error in x + y : non-numeric argument to binary operator
Pokud vám automatické vrácení hodnoty posledního výrazu nevyhovuje, je možné použít i konstrukci return, podobně, jako je tomu v mnoha dalších programovacích jazycích:
help(return)
Ovšem je nutné si dát pozor na to, že v R je nutné psát výraz (jehož hodnota se má vrátit) do závorek:
f1 <- function() { return 42 }
Předchozí kód je napsán chybně:
Error: unexpected numeric constant in:
Korektní zápis konstrukce return vypadá takto:
f1 <- function() { return(42) } f1() 42
Podívejme se nyní na složitější příklad, v němž je ve funkci použita minule popsaná rozhodovací konstrukce if-else:
classify.number <- function(x) { if (x > 0) { result <- "Positive" } else if (x < 0) { result <- "Negative" } else { result <- "Zero" } return(result) }
Tato funkce vrací hodnoty podle očekávání:
> classify.number(-100) [1] "Negative" > classify.number(0) [1] "Zero" > classify.number(100) [1] "Positive"
Konstrukce return se ovšem nemusí nacházet pouze na konci funkce, což si ukážeme na upravené verzi funkce classify.number:
classify.number <- function(x) { if (x > 0) { return("Positive") } else if (x < 0) { return("Negative") } else { return("Zero") } }
Výsledky budou stejné, jako v předchozí funkci:
> classify.number(-100) [1] "Negative" > classify.number(0) [1] "Zero" > classify.number(100) [1] "Positive"
4. Pojmenované parametry volaných funkcí
Připomeňme si ještě jednou funkci pro součet dvou čísel:
add <- function(x, y) { x+y }
Při volání této funkce můžeme (pochopitelně) předávat poziční parametry::
> add(10, 20) [1] 30
Parametry je ovšem možné při volání pojmenovat:
> add(x=10, y=20) [1] 30
Což nám umožňuje nedodržet pořadí parametrů:
> add(y=20, x=100) [1] 120
Umožněna je i libovolná kombinace pozičních a pojmenovaných parametrů, přičemž jsou poziční parametry postupně dosazovány tak, aby vyplnily místa neobsazená pojmenovanými parametry:
> add(x=100, 0) [1] 100
I tento zápis je v jazyku R zcela korektní:
> add(y=100, 0) [1] 100
5. Nepovinné parametry s výchozí hodnotou
V definici funkce u některých parametrů (nebo i všech parametrů) můžeme specifikovat výchozí (default) hodnotu:
pow <- function(x, y=2) { result <- x ^ y return(result) }
Alternativní (kratší) způsob zápisu této funkce:
pow <- function(x, y=2) { x^y }
Takovou funkci je možné volat s oběma pozičními parametry:
> pow(2,2) [1] 4
Výchozí parametr je možné vynechat:
> pow(2) [1] 4
Opět vynechání výchozího parametru, ovšem první parametr je pojmenován:
> pow(x=3) [1] 9
Kombinace obou předchozích způsobů (pojmenování parametrů atd.):
> pow(y=3, 3) [1] 27 > pow(y=10, x=2) [1] 1024
6. Anonymní funkce
Kromě běžných (pojmenovaných) funkcí popsaných v předchozích kapitolách je možné v programovacím jazyce R, podobně jako v mnoha dalších jazycích umožňujících funkcionální programování, vytvářet a používat takzvané funkce anonymní. Tyto funkce, které je možné s výhodou využít například při zápisu iterací nad prvky seznamů či při omezování oblasti platnosti proměnných, se vytváří opět s využitím konstrukce function (v jiných programovacích jazycích se ovšem setkáme s konstrukcí lambda, jejíž název je odvozen ze slavné Churchovy teorie Lambda kalkulu, která má poměrně velký význam jak v teoretické informatice, tak i v dalších odvětvích informatiky.
Samotný zápis anonymní funkce se příliš neliší od zápisu funkce pojmenované, pouze se funkce nepřiřazuje do proměnné, ale například se přímo volá tak, jako je tomu v následujícím jednoduchém demonstračním příkladu:
> (function(x) x*x)(5) [1] 25
Povšimněte si toho, že samotný zápis funkce je umístěn do kulatých závorek, což je nutné z hlediska syntaxe – anonymní funkci voláme s nějakým parametrem umístěným za její definicí.
7. Zavolání funkce pro všechny prvky seznamů nebo vektorů
Velmi často se setkáme s požadavkem na aplikaci (zavolání) nějaké funkce postupně pro všechny prvky vektoru nebo seznamu s tím, že výsledkem bude nový vektor nebo seznam. Pro tento účel existuje v programovacím jazyku R dvojice funkcí vyššího řádu nazvaných sapply a lapply:
> help(sapply) lapply package:base R Documentation Apply a Function over a List or Vector Description: ‘lapply’ returns a list of the same length as ‘X’, each element of which is the result of applying ‘FUN’ to the corresponding element of ‘X’. ‘sapply’ is a user-friendly version and wrapper of ‘lapply’ by default returning a vector, matrix or, if ‘simplify = "array"’, an array if appropriate, by applying ‘simplify2array()’. ‘sapply(x, f, simplify = FALSE, USE.NAMES = FALSE)’ is the same as ‘lapply(x, f)’. ‘vapply’ is similar to ‘sapply’, but has a pre-specified type of return value, so it can be safer (and sometimes faster) to use. ‘replicate’ is a wrapper for the common use of ‘sapply’ for repeated evaluation of an expression (which will usually involve random number generation). ‘simplify2array()’ is the utility called from ‘sapply()’ when ‘simplify’ is not false and is similarly called from ‘mapply()’. Usage: lapply(X, FUN, ...) sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE) vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE) replicate(n, expr, simplify = "array") simplify2array(x, higher = TRUE)
Naši funkci pow pro výpočet n-té mocniny:
pow <- function(x, y=2) { result <- x ^ y return(result) }
tedy můžeme postupně aplikovat na prvky sekvence s hodnotami 1, 2, … 10 s tím, že se výsledek „zjednoduší“ na seznam:
> sapply(1:10, pow) [1] 1 4 9 16 25 36 49 64 81 100
Pokud namísto funkce sapply použijeme funkci lapply, bude výpočet probíhat stejným způsobem, ale výsledek bude odlišný – vrátí se jednoprvkové seznamy s výsledky:
> lapply(1:10, pow) [[1]] [1] 1 [[2]] [1] 4 [[3]] [1] 9 [[4]] [1] 16 [[5]] [1] 25 [[6]] [1] 36 [[7]] [1] 49 [[8]] [1] 64 [[9]] [1] 81 [[10]] [1] 100
8. Kombinace anonymní funkce a funkcí vyššího řádu sapply či lapply
Poměrně často se setkáme i s použitím anonymní funkce (viz šestou kapitolu) jakožto parametru funkce vyššího řádu sapply či lapply. Druhé mocniny hodnot 1..10 lze vypočítat i takto:
> sapply(1:10, function(x) x*x) [1] 1 4 9 16 25 36 49 64 81 100
Častěji se ovšem setkáme s tím, že je tělo funkce uzavřeno do složených závorek:
> sapply(1:10, function(x) {x*x}) [1] 1 4 9 16 25 36 49 64 81 100
Popř. se použije konstrukce return, a to buď uvnitř složených závorek, nebo i bez nich:
> sapply(1:10, function(x) {return (x*x)}) [1] 1 4 9 16 25 36 49 64 81 100 > sapply(1:10, function(x) return (x*x)) [1] 1 4 9 16 25 36 49 64 81 100
Kombinace více volání funkce sapply:
> sapply(1:10, function(x) x*x) [1] 25 16 9 4 1 0 1 4 9 16 25
9. Prostředí (environment)
Příkazy uvnitř těla funkce jsou vykonávány v rámci nějakého prostředí (environment). Toto prostředí určuje proměnné, které jsou v rámci těla funkce (nebo mimo něj) viditelné. Tyto dostupné (viditelné) proměnné lze zjistit s využitím funkce ls:
> help(ls)
Pokud tedy vytvoříme nějaké proměnné:
> a <- 1 > b <- 2 > f <- function(x) x<-0
Měla by funkce ls vrátit vektor s trojicí jmen těchto proměnných:
> ls() [1] "a" "b" "f"
Viditelnost proměnných (a pojmenované funkce jsou taktéž proměnné) můžeme zjistit i v případě, že jedna funkce je vnořena do funkce jiné, což je pochopitelně možné (pokud by tomu tak nebylo, nebyly by funkce plnohodnotnými datovými typy – mnohé jazyky ovšem toto omezení mnohdy poněkud uměle zavádí):
f1 <- function(param_f1) { f2 <- function(param_f2) { print("f2") print(environment()) print(ls()) } f2(42) print("f1") print(environment()) print(ls()) } f1()
Vidíme, že uvnitř funkce můžeme vidět a tedy i přistupovat k jejím parametrům; interní funkce je považována za běžnou lokální proměnnou:
[1] "f2" <environment: 0x55cf4d95fd58> [1] "param_f2" [1] "f1" <environment: 0x55cf4d95ff18> [1] "f2" "param_f1"
Operátor ← již známe: používá se pro přiřazení hodnoty do proměnné, která je v případě potřeby vytvořena. Díky tomu, že každé volání funkce vytvoří nové prostředí, budou i proměnné vytvořené s využitím ← pouze lokální v rámci daného prostředí, což je většinou přesně takové chování, které požadujeme:
x <- 10 f3 <- function(param_f3) { x <- 20 print(x) f4 <- function(param_f4) { x <- 30 print(x) } f4() print(x) } print(x) f3() print(x)
Z výsledků je patrné, že jen první přiřazení bylo provedeno do globální proměnné x, zatímco druhé přiřazení se týká lokální proměnné funkce f3 a třetí přiřazení proměnné lokální v rámci funkce f4 (která je navíc sama lokálně viditelná jen ve funkci f3:
> print(x) [1] 10 > f3() [1] 20 [1] 30 [1] 20 > print(x) [1] 10
10. Přístup k nelokálním proměnným
V některých případech (jeden takový uvidíme dále při implementaci čítače s využitím uzávěru) je nutné měnit hodnotu nelokálních proměnných. V takovém případě se namísto operátoru přiřazení ← použije operátor „superpřiřazení“, který se zapisuje <<-. Tento operátor postupně prochází dostupnými prostředími a hledá, zda daná proměnná již existuje či nikoli. Pokud tedy v předchozím příkladu použijeme operátor „superpřiřazení“, změní se i jeho chování, a to poměrně zásadním způsobem:
x <- 10 f5 <- function(param_f3) { x <<- 20 print(x) f6 <- function(param_f4) { x <<- 30 print(x) } f6() print(x) } print(x) f5() print(x)
Chování lze sledovat z výstupu:
> print(x) [1] 10 > f5() [1] 20 [1] 30 [1] 30 > print(x) [1] 30
Můžeme vidět, že se nejdříve vypíše hodnota globální proměnné (10), dále se tato hodnota ve funkci f5 změní na 20, v dalším kroku ve funkci f6 dojde ke změně na 30 a tato hodnota je již zachována. Operátor <<- nám tedy umožnil změnit hodnotu globální proměnné (což je ovšem obecně problematický rys, který by se neměl zneužívat).
11. Lexikální uzávěry
Připomeňme si, že v programovacím jazyce R jsou funkce považovány za plnohodnotné datové typy, což znamená, že funkce lze navázat na libovolný symbol (a tím vlastně původně anonymní funkci pojmenovat), funkce lze předávat jako parametry do jiných funkcí a funkce mohou být taktéž návratovou hodnotou jiných funkcí – funkce tedy může vytvořit a vrátit jinou funkci. R taktéž podporuje práci s uzávěry (closure(s)), tj. funkcí svázaných s nějakým symbolem vytvořeným vně funkce.
Podpora uzávěrů umožňuje například tvorbu funkcí sdílejících společný kontext (GUI) atd. Ovšem vzhledem k tomu, že – jak již víme – R není čistě funkcionálním jazykem, je možné při vytváření uživatelských funkcí přímo z dané funkce přistupovat k nějakému globálnímu symbolu, přesněji řečeno k symbolu „globálnímu“ v rámci nějakého jmenného prostoru. Taktéž lze vytvářet funkce s vedlejším efektem, které například zapisují data do souborů, mění hodnotu navázanou na globální symboly atd.
Podívejme se na příklad jednoduchého, ale praktického využití uzávěrů. Jedná se o konstruktor funkcí „výpočet n-té mocniny“, kde n je specifikováno při konstrukci funkce:
pow_x <- function(x) { function(y) { y ^ x } }
Můžeme si například nechat vytvořit funkci pro výpočet druhé mocniny. Vytvoření (konstrukce) takové funkce vypadá následovně:
> square <- pow_x(2)
Následně již můžeme novou (pojmenovanou!) funkci použít stejně, jako jakoukoli jinou funkci:
> square(3) 9
Další použití, tentokrát pro sekvenci hodnot:
> sapply(1:10, square) [1] 2 4 8 16 32 64 128 256 512 1024
Více zkonstruovaných funkcí:
pow_x <- function(x) { function(y) { y ^ x } } linear <- pow_x(1) square <- pow_x(2) cube <- pow_x(3) for (x in 1:10) { print(c(x, linear(x), square(x), cube(x))) }
S výsledkem:
[1] 1 1 1 1 [1] 2 2 4 8 [1] 3 3 9 27 [1] 4 4 16 64 [1] 5 5 25 125 [1] 6 6 36 216 [1] 7 7 49 343 [1] 8 8 64 512 [1] 9 9 81 729 [1] 10 10 100 1000
12. Klasický příklad uzávěru – čítač (generátor sekvence)
Podívejme se nyní na dnes již zcela klasický příklad využití uzávěru. Jedná se o implementaci čítače (nebo obecněji generátoru nějaké sekvence hodnot, který pro svoji funkci potřebuje interní paměť pro zapamatování svého stavu). Čítač je představován uzávěrem zkonstruovaným funkcí counter. Funkce v uzávěru přistupuje k navázané proměnné n, kterou zvyšuje o jedničku a současně její hodnotu vrací:
counter <- function() { n <- 0 function() { n <<- n + 1 n } }
Čítač si nejprve necháme zkonstruovat:
> c1 <- counter()
Volání counter() vrátilo uzávěr, při jehož zavolání dojde ke změně vnitřního stavu a posléze se vrátí nová hodnota čítače:
> c1() [1] 1 > c1() [1] 2 > c1() [1] 3
Interní hodnota čítače v žádném případě není obdobou statických lokálních proměnných z céčka, o čemž se můžeme snadno přesvědčit vytvořením dalších dvou na sobě nezávislých čítačů:
> c2 <- counter() > c3 <- counter()
Všechny tři čítače skutečně pracují nezávisle na sobě:
> c1() [1] 4 > c2() [1] 1 > c3() [1] 1 > c1() [1] 5 > c2() [1] 2 > c3() [1] 2 > c1() [1] 6 > c2() [1] 3 > c3() [1] 3
13. Čítač s předem nastaveným krokem
Předchozí uzávěr pracoval s navázanou proměnnou n, ovšem můžeme vytvořit i uzávěr, který pracuje s hodnotu svého parametru. V praxi si například můžeme vytvořit čítač, u něhož je možné specifikovat krok. Jedná z možných implementací může vypadat následovně:
counter <- function(step=1) { n <- 0 function() { n <<- n + step n } }
Nový typ čítače si můžeme snadno otestovat:
> c0 <- counter(2) > c0() [1] 2 > c0() [1] 4 > c0() [1] 6 > c0() [1] 8
Několik na sobě nezávislých čítačů, každý s jiným krokem:
c1 <- counter(1) c2 <- counter(2) c3 <- counter(3) c4 <- counter(4)
Nové čítače použijeme – opět budou na sobě nezávislé:
for (i in 1:10) { print(c(c1(), c2(), c3(), c4())) } [1] 1 2 3 4 [1] 2 4 6 8 [1] 3 6 9 12 [1] 4 8 12 16 [1] 5 10 15 20 [1] 6 12 18 24 [1] 7 14 21 28 [1] 8 16 24 32 [1] 9 18 27 36 [1] 10 20 30 40
14. Rekurzivní funkce
Naprostá většina dnes používaných mainstreamových programovacích jazyků podporuje tvorbu rekurzivních funkcí. Výjimkou není ani jazyk R, takže si ukažme typickou funkci, která se používá při výuce programování. Jedná se o rekurzivní variantu výpočtu faktoriálu:
fact <- function(n) { if (n == 0 || n == 1) { return (1) } else { return (n * fact(n - 1)) } }
Otestování funkcionality:
> fact(10) [1] 3628800
Výpočet faktoriálů vstupních hodnot od 1 do 10:
> lapply(1:10, fact) [[1]] [1] 1 [[2]] [1] 2 [[3]] [1] 6 [[4]] [1] 24 [[5]] [1] 120 [[6]] [1] 720 [[7]] [1] 5040 [[8]] [1] 40320 [[9]] [1] 362880 [[10]] [1] 3628800
Vzhledem k tomu, že se jedná o rekurzivní funkci bez aplikovaného TCO (tail call optimization), dojde pro větší vstupní hodnoty k vyčerpání paměti určené pro implementaci zásobníku, resp. přesněji řečeno zásobníkových rámců:
> fact(10000) Error: C stack usage 7978740 is too close to the limit
Podporována je i nepřímá rekurze, tedy stav, kdy jedna funkce volá druhou a ta zase první:
f1 <- function(x) { print(x) if (x>0) { f2(x-1) } 0 } f2 <- function(x) { print(x) f1(x/2) }
Otestování:
> f2(10) [1] 10 [1] 5 [1] 4 [1] 2 [1] 1 [1] 0.5 [1] -0.5 [1] -0.25 [1] 0
15. Funkce vyššího řádu v programovacím jazyce R
Programovací jazyk R sice není, na rozdíl od Haskellu a částečně i od programovacího jazyka Clojure, čistě funkcionálním jazykem, nicméně i zde mohou hrát při vývoji aplikací poměrně velkou roli takzvané funkce vyššího řádu (higher order functions), což jsou funkce, které jako své parametry akceptují jiné funkce, popř. dokonce vrací (nové) funkce jako svoji návratovou hodnotu. Mezi dvě základní funkce vyššího řádu, které nalezneme prakticky ve všech dialektech programovacího jazyka Lisp (a připomeňme si, že R vychází ze Scheme, tedy z jedné varianty LISPu), patří funkce nazvané Reduce, Filter a Map. Kromě toho lze používat i další funkce vyššího řádu, například Find či Negate:
Reduce(f, x, init, right = FALSE, accumulate = FALSE) Filter(f, x) Find(f, x, right = FALSE, nomatch = NULL) Map(f, ...) Negate(f) Position(f, x, right = FALSE, nomatch = NA_integer_)
S použitím funkcí vyššího řádu se seznámíme v navazujících kapitolách.
16. Funkce Reduce
Dvěma základními funkcemi vyššího řádu, které nesmějí chybět v repertoáru žádné funkcionálně zaměřené knihovny, je dvojice funkcí typicky pojmenovaná reduce a reduceRight (někdy se setkáme s názvy foldl a foldr atd.). Názvy těchto funkcí naznačují jejich účel – dochází k postupné redukci prvků uložených v kolekci či v poli, a to (postupnou) aplikací zvolené uživatelské funkce na jednotlivé prvky a po krocích počítaný mezivýsledek. Mezi reduce a reduceRight je rozdíl v tom, ze které strany původní kolekce dochází ke kýžené redukci.
Podívejme se nyní na typický „školní“ příklad, v němž se sečtou všechny prvky v aritmetické řadě 1..10. Nejprve vytvořme tuto řadu:
s <- 1:10
Následně vytvořme uživatelskou funkci, která se bude volat pro každý prvek původní kolekce a pro mezivýsledek. Jedná se o značně jednoduchou funkci, které pouze obě předané hodnoty sečte:
add <- function(x, y) { x+y }
Nyní zajistíme postupné volání funkce add na prvky sekvence s automatickým předáním mezivýsledku. Podle předpokladů bude výsledek funkce reduce v tomto případě totožný s výsledkem vráceným funkcí typu reduceRight, protože je zcela jedno, v jakém pořadí se prvky sečtou:
Reduce(add, s) 55
Následuje nepatrně složitější příklad – výpočet tabulky faktoriálů pro vstupy od 1 do 10 (včetně):
mul <- function(x, y) { x*y } fact <- function(n) { Reduce(mul, 1:n) } sapply(1:10, fact)
17. Redukce zprava
Jazyk R ve své základní knihovně neobsahuje přímo funkci pro redukci sekvence zprava, tedy funkci, která se běžně nazývá reduceRight. Namísto toho je možné funkci Reduce předat parametr right:
s <- 1:10 add <- function(x, y) { x+y } Reduce(add, s, right=TRUE)
Ne všechny operace jsou ovšem asociativní a komutativní, jako je tomu u součtu čísel. Zkusme si vyzkoušet, co se stane ve chvíli, kdy namísto sčítání čísel budeme používat umocnění. Zde je rozdíl mezi redukcí zleva a redukcí zleva jasně patrný:
s <- c(2, 2, 3) pow <- function(x, y) { x^y } Reduce(pow, s) [1] 64 Reduce(pow, s, right=TRUE) [1] 256
18. Balíčky s alternativní formou definice funkcí
Do programovacího jazyka R je možné relativně snadno přidávat další konstrukce. Týká se to i definice, popř. volání funkcí, a to i funkcí anonymních. V současnosti existuje hned několik balíčků s alternativní podobou definice funkcí. Tyto balíčky jsou zmíněny v tabulce a některým z nich se budeme věnovat v následujícím pokračování tohoto seriálu:
# | Balíček | Forma | Funkce s jedním parametrem | Funkce se dvěma parametry | Explicitní parametry | Jména parametrů |
---|---|---|---|---|---|---|
1 | base r | function | function(x) x + 1 | function(x, y) x + y | Ano | Explicitní |
2 | rlang | as_function | as_function(~.x + 1)) | as_function(~.x+.y) | Ne | Implicitní. jen .x or .y |
3 | pryr | f (implicitní parametry) | f(x + 1) | f(x + y) | Ne | Implicitní, odvozeno z těla funkce |
4 | pryr | f (explicitní parametry) | f(x, x + 1) | f(x, y, x + y) | Ano | Explicitní |
5 | nofrills | fn | fn(x ~ x + 1) | fn(x, y ~ x + y) | Ano | Explicitní |
6 | gsubfn | as.function.formula (implicitní parametry) | as.function.formula(~ x + 1) | as.function.formula(~ x + y) | Ne | Implicitní, odvozeno z pravé strany výrazu |
7 | gsubfn | as.function.formula (explicitní parametry) | as.function.formula(x ~ x + 1) | as.function.formula(x + y ~ x + y + z) | Ano | Explicitní, odvozeno z levé strany výrazu |
8 | wrapr | lambda | lambda(x, x + 1) | lambda(x, y, x + y) | Ano | Explicitní |
9 | lambda | f | f(.(x) + 1) | f(.(x) + .(y)) | Ne | Implicitní, odvozeno z výrazu |
10 | lambdass | ~~ | ~~ ..1 + 1 | ~~ ..1 + ..2 | No | Implicitní, povoleno použití ..N zápisu |
11 | lambdass | f.() | f.(x, x + 1) | f.(x, y, x + y) | Ano | Explicitní |
12 | lambdass | %->% | f(x) %->% {x + 1} | f(x, y) %->% {x + y} | Ano | Explicitní |
13 | functional | “->” | NA | x ~ y → x + y | Ano | Explicitní |
14 | ne (ve fázi návrhu) | lambda | lambda(x ~ x + 1L) | lambda(x + y ~ x + y) | Ano | Explicitní, odvozeno z levé strany výrazu |
15 | ne (ve fázi návrhu) | lambda | lambda(x:x + 1) | lambda(x, y:x + y) | Ano | Explicitní |
16 | ne (ve fázi návrhu) | [] -> | [x] → x + 1 | [x, y] → x + y | Ano | Explicitní |
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/r-examples V případě, že z nějakého důvodu nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má stále jen jednotky kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:
20. Odkazy na Internetu
- R Tutorial
https://www.tutorialspoint.com/r/index.htm - A Tutorial on Using Functions in R!
https://www.datacamp.com/community/tutorials/functions-in-r-a-tutorial - R Functions
https://www.datamentor.io/r-programming/function/ - A Tutorial on Loops in R – Usage and Alternatives
https://www.datacamp.com/community/tutorials/tutorial-on-loops-in-r - Anonymous Functions in R – Part 1
https://coolbutuseless.github.io/2019/03/13/anonymous-functions-in-r-part-1/ - Anonymous Functions in R – Part 2
https://coolbutuseless.github.io/2019/03/13/anonymous-functions-in-r-part-2/ - Scoping and Closures in R
https://www.pluralsight.com/guides/scoping-and-closures-in-r - Tools for Computing on the Language
https://www.rdocumentation.org/packages/pryr/versions/0.1.4 - Difference between double-precision data type and numeric data type
https://stackoverflow.com/questions/50255318/difference-between-double-precision-data-type-and-numeric-data-type - R Data Types
https://www.w3schools.in/r/data-types/ - What is the difference between mode and class in R?
https://stackoverflow.com/questions/35445112/what-is-the-difference-between-mode-and-class-in-r - switch: Select One of a List of Alternatives
https://rdrr.io/r/base/switch.html - R switch() Function
https://www.datamentor.io/r-programming/switch-function/ - Using ggplot in Python: Visualizing Data With plotnine
https://realpython.com/ggplot-python/ - A Grammar of Graphics for Python
https://plotnine.readthedocs.io/en/stable/ - Plotnine gallery
https://plotnine.readthedocs.io/en/latest/gallery.html - plotnine 0.7.1 na PyPi
https://pypi.org/project/plotnine/ - plotnine-examples 0.0.4 na PyPi
https://pypi.org/project/plotnine-examples/ - plotnine examples repository
https://github.com/has2k1/plotnine-examples - Data visualization in R: cheat sheet
https://github.com/rstudio/cheatsheets/blob/master/data-visualization-2.1.pdf - The R Project for Statistical Computing
https://www.r-project.org/ - An Introduction to R
https://cran.r-project.org/doc/manuals/r-release/R-intro.pdf - R (programming language)
https://en.wikipedia.org/wiki/R_(programming_language) - The R Programming Language
https://www.tiobe.com/tiobe-index/r/ - R Graphics Second Edition
https://www.stat.auckland.ac.nz/~paul/RG2e/ - ggplot2 – Introduction
https://www.tutorialspoint.com/ggplot2/ggplot2_introduction.htm - ggplot2: Elegant Graphics for Data Analysis
https://ggplot2-book.org/index.html - Create Elegant Data Visualisations Using the Grammar of Graphics
https://www.rdocumentation.org/packages/ggplot2/versions/3.3.2 - Grid
https://www.stat.auckland.ac.nz/~paul/grid/grid.html - Interactive Course: Data Visualization with lattice in R
https://www.datacamp.com/courses/data-visualization-in-r-with-lattice - Lattice: trellis graphics for R
https://lattice.r-forge.r-project.org/ - Lattice: Multivariate Data Visualization with R
http://lmdvr.r-forge.r-project.org/figures/figures.html - Getting Started with Lattice Graphics
https://lattice.r-forge.r-project.org/Vignettes/src/lattice-intro/lattice-intro.pdf - Using lattice’s xyplot()
https://homerhanumat.github.io/tigerstats/xyplot.html - ggplot2 Tutorial
https://www.tutorialspoint.com/ggplot2/index.htm - Lattice Package in R with Functions and Graphs
https://techvidvan.com/tutorials/lattice-package-in-r/ - The R Graph Gallery
https://www.r-graph-gallery.com/index.html - Lattice Graphs
https://www.statmethods.net/advgraphs/trellis.html - ggplot2 (Graph gallery)
https://www.r-graph-gallery.com/ggplot2-package.html - R Markdown
https://rmarkdown.rstudio.com/ - R Markdown: The Definitive Guide
https://bookdown.org/yihui/rmarkdown/ - R Markdown Cheat Sheet
https://rstudio.com/wp-content/uploads/2016/03/rmarkdown-cheatsheet-2.0.pdf - Introduction to R Markdown
https://rmarkdown.rstudio.com/articles_intro.html - R Cheat Sheets
https://blog.sergiouri.be/2016/07/r-cheat-sheets.html - R Cheat Sheet
https://s3.amazonaws.com/quandl-static-content/Documents/Quandl±+R+Cheat+Sheet.pdf - Base R Cheat Sheet
https://rstudio.com/wp-content/uploads/2016/06/r-cheat-sheet.pdf - PYPL PopularitY of Programming Language
https://pypl.github.io/PYPL.html - Tiobe index
https://www.tiobe.com/tiobe-index/ - Stack Overflow: Most Loved, Dreaded & Wanted Programming Languages In 2020
https://fossbytes.com/stack-overflow-most-loved-dreaded-wanted-programming-languages-in-2020/ - How to Install and Use R on Ubuntu
https://itsfoss.com/install-r-ubuntu/ - R programming for beginners – Why you should use R
https://www.youtube.com/watch?v=9kYUGMg_14s - GOTO 2012 • The R Language The Good The Bad & The Ugly
https://www.youtube.com/watch?v=6S9r_YbqHy8 - Intro to Data Visualization with R & ggplot2
https://www.youtube.com/watch?v=49fADBfcDD4 - Plotting with ggplot2: Part 1
https://www.youtube.com/watch?v=HeqHMM4ziXA - Plotting with ggplot2: Part 2
https://www.youtube.com/watch?v=n8kYa9vu1l8 - R vs Python – What should I learn in 2020? | R and Python Comparison
https://www.youtube.com/watch?v=eRP_J2yLjSU - R Programming 101
https://www.youtube.com/c/rprogramming101 - Seriál Tvorba grafů pomocí programu „R“
https://www.root.cz/serialy/tvorba-grafu-pomoci-programu-r/ - Tvorba grafů pomocí programu „R“: úvod
https://www.root.cz/clanky/tvorba-grafu-pomoci-programu-r-1/ - Tvorba grafů pomocí programu „R“: pokročilé funkce
https://www.root.cz/clanky/tvorba-grafu-pomoci-programu-r-pokrocile-funkce/ - Tvorba grafů pomocí programu „R“: vkládání textu, čeština
https://www.root.cz/clanky/grafy-pomoci-programu-r-vkladani-textu-cestina/ - Cesta erka: Krok nultý – instalace & nastavení – prostředí, projekty, package
https://www.jla-data.net/r4su/r4su-environment-setup/ - Cesta erka: Krok první – operace a struktury – proměnné, rovnítka a dolary
https://www.jla-data.net/r4su/r4su-data-structures/ - Cesta erka: Krok druhý – načtení externích dat – csvčka, excely a databáze
https://www.jla-data.net/r4su/r4su-read-data/ - Cesta erka: Krok třetí – manipulace s daty – dplyr, slovesa a pajpy
https://www.jla-data.net/r4su/r4su-manipulate-data/ - Cesta erka: Krok čtvrtý – podání výsledků – ggplot, geomy a estetiky
https://www.jla-data.net/r4su/r4su-report-results/ - Cesta erka: Krok pátý – case study – případ piva v Praze
https://www.jla-data.net/r4su/r4su-case-study-beer/ - V indexu popularity programovacích jazyků TIOBE překvapilo R, Go, Perl, Scratch a Rust
https://www.root.cz/zpravicky/v-indexu-popularity-programovacich-jazyku-tiobe-prekvapilo-r-go-perl-scratch-a-rust/ - Is R Programming SURGING in Popularity in 2020?
https://www.youtube.com/watch?v=Duwn-vImyXE - Using the R programming language in Jupyter Notebook
https://docs.anaconda.com/anaconda/navigator/tutorials/r-lang/ - Using R on Jupyter Notebook
https://dzone.com/articles/using-r-on-jupyternbspnotebook - Graphics, ggplot2
http://r4stats.com/examples/graphics-ggplot2/ - A Practice Data Set
https://r4stats.wordpress.com/examples/mydata/ - Shiny – galerie projektů
https://shiny.rstudio.com/gallery/ - Seriál Programovací jazyk Julia
https://www.root.cz/serialy/programovaci-jazyk-julia/ - Julia (front page)
http://julialang.org/ - Julia – repositář na GitHubu
https://github.com/JuliaLang/julia - Julia (programming language)
https://en.wikipedia.org/wiki/Julia_%28programming_language%29 - IJulia
https://github.com/JuliaLang/IJulia.jl - Introducing Julia
https://en.wikibooks.org/wiki/Introducing_Julia - Julia: the REPL
https://en.wikibooks.org/wiki/Introducing_Julia/The_REPL - Introducing Julia/Metaprogramming
https://en.wikibooks.org/wiki/Introducing_Julia/Metaprogramming - Month of Julia
https://github.com/DataWookie/MonthOfJulia - Learn X in Y minutes (where X=Julia)
https://learnxinyminutes.com/docs/julia/ - New Julia language seeks to be the C for scientists
http://www.infoworld.com/article/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html - Julia: A Fast Dynamic Language for Technical Computing
http://karpinski.org/publications/2012/julia-a-fast-dynamic-language - The LLVM Compiler Infrastructure
http://llvm.org/ - Julia: benchmarks
http://julialang.org/benchmarks/ - R Vector
https://www.datamentor.io/r-programming/vector/ - .R File Extension
https://fileinfo.com/extension/r - Lineární regrese
https://cs.wikipedia.org/wiki/Line%C3%A1rn%C3%AD_regrese - lm (funkce)
https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/lm - quit (funkce)
https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/quit - c (funkce)
https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/c - help (funkce)
https://www.rdocumentation.org/packages/utils/versions/3.6.2/topics/help - Shiny: Introduction to interactive documents
https://shiny.rstudio.com/articles/interactive-docs.html - R Release History 1997–2013
http://timelyportfolio.github.io/rCharts_timeline_r/ - R: atomic vectors
https://renenyffenegger.ch/notes/development/languages/R/data-structures/vector/ - 11 Best R Programming IDE and editors
https://www.dunebook.com/best-r-programming-ide/ - CRAN – The Comprehensive R Archive Network
https://cran.r-project.org/ - R – Arrays
https://www.tutorialspoint.com/r/r_arrays.htm - Array vs Matrix in R Programming
https://www.geeksforgeeks.org/array-vs-matrix-in-r-programming/?ref=rp - Online R Language IDE
https://www.jdoodle.com/execute-r-online/ - Execute R Online (R v3.4.1)
https://www.tutorialspoint.com/execute_r_online.php - Snippets: Run any R code you like. There are over twelve thousand R packages preloaded
https://rdrr.io/snippets/ - R Package Documentation
https://rdrr.io/ - Data Reshaping in R – Popular Functions to Organise Data
https://techvidvan.com/tutorials/data-reshaping-in-r/ - What is an R Data Frame?
https://magoosh.com/data-science/what-is-an-r-data-frame/ - What's a data frame?
https://campus.datacamp.com/courses/free-introduction-to-r/chapter-5-data-frames?ex=1 - data.frame
https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/data.frame - as.data.frame
https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/as.data.frame - table
https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/table - Python Pandas – DataFrame
https://www.tutorialspoint.com/python_pandas/python_pandas_dataframe.htm - The Pandas DataFrame: Make Working With Data Delightful
https://realpython.com/pandas-dataframe/ - Python | Pandas DataFrame
https://www.geeksforgeeks.org/python-pandas-dataframe/ - R – Factors
https://www.tutorialspoint.com/r/r_factors.htm - R – Scatterplots
https://www.tutorialspoint.com/r/r_scatterplots.htm - Quick guide to line types (lty) in R
https://www.benjaminbell.co.uk/2018/02/quick-guide-to-line-types-lty-in-r.html - Lattice C (Wikipedia)
https://en.wikipedia.org/wiki/Lattice_C - Lorenz Attractor in R
https://www.sixhat.net/lorenz-attractor-in-r.html - Small multiple
https://en.wikipedia.org/wiki/Small_multiple - Category:Infographics (infografika)
https://en.wikipedia.org/wiki/Category:Infographics - Trellis plots (pro Python)
https://subscription.packtpub.com/book/big_data_and_business_intelligence/9781784390150/4/ch04lvl1sec41/trellis-plots - Trellis (architecture)
https://en.wikipedia.org/wiki/Trellis_(architecture) - Izobara (meteorologie)
https://cs.wikipedia.org/wiki/Izobara_(meteorologie) - How to Create a Lattice Plot in R
https://www.dummies.com/programming/r/how-to-create-a-lattice-plot-in-r/ - Density estimation
https://en.wikipedia.org/wiki/Density_estimation - Sedm smrtelných statistických hříchů
http://dfens-cz.com/sedm-smrtelnych-statistickych-hrichu/ - Spurious correlations
https://tylervigen.com/spurious-correlations - R programming
https://www.slideshare.net/shantanupatil104/r-programming-44637606 - R language tutorial
https://www.slideshare.net/ChiuYW/r-language-tutorial - An Interactive Introduction To R (Programming Language For Statistics)
https://www.slideshare.net/dataspora/an-interactive-introduction-to-r-programming-language-for-statistics - A Pamphlet against R
https://panicz.github.io/pamphlet/ - Notebook interface
https://en.wikipedia.org/wiki/Notebook_interface - Jypyter: open source, interactive data science and scientific computing across over 40 programming languages
https://jupyter.org/ - nbviewer: a simple way to share Jupyter Notebooks
https://nbviewer.jupyter.org/ - Video streaming in the Jupyter Notebook
https://towardsdatascience.com/video-streaming-in-the-jupyter-notebook-635bc5809e85 - How IPython and Jupyter Notebook work
https://jupyter.readthedocs.io/en/latest/architecture/how_jupyter_ipython_work.html - Jupyter kernels
https://github.com/jupyter/jupyter/wiki/Jupyter-kernels - PNG is Not GIF
https://www.root.cz/clanky/png-is-not-gif/ - Anatomie grafického formátu PNG
https://www.root.cz/clanky/anatomie-grafickeho-formatu-png/ - PNG – bity, byty, chunky
https://www.root.cz/clanky/png-bity-byty-chunky/ - Řádkové filtry v PNG
https://www.root.cz/clanky/radkove-filtry-v-png/ - Nepovinné chunky v PNG a kontrola pomocí CRC
https://www.root.cz/clanky/nepovinne-chunky-v-png-a-kontrola-pomoci-crc/