Дефинисање функција
У програмском језику R функција се дефинише на следећи
начин:
function_name <- function(arg1, arg2, arg3, ...) {function body}.
Функција се позива са function_name(arg1, arg2, ...) са
конкретним аргументима.
function_name <- function(parameters){
function body
}
Ако желимо да видимо код постојећих функција, куцамо само име функције без аргумената.
## function (x)
## gamma(x + 1)
## <bytecode: 0x0000021688a18780>
## <environment: namespace:base>
- Функција која рачуна биномни коефицијент \(\binom{n}{k}\).
binomni <- function(n, k){
koef <- factorial(n) / (factorial(k) * factorial(n-k))
return(koef)
}
binomni(4, 2)## [1] 6
Када позивамо функцију, аргументе наводимо истим редом као у дефиницији функције, осим ако их наведемо по имену. Тада је редослед произвољан.
## [1] 6
## [1] 6
binomni(2, 4)
Warning in gamma(x + 1) : NaNs produced
- Функција која спаја два вектора као колоне матрице.
## v1 v2
## [1,] 0 0
## [2,] 1 1
## [3,] 2 2
## [4,] 3 3
Функција не мора да садржи RETURN наредбу, може само да
се направе неке измене које важе само у телу функције.
- Функција која рачуна квадрат броја
## [1] 9
## [1] 3
- Функција која рачуна површину круга.
## [1] 12.56637
- Задавање вредности аргументима функције.
my_faculty <- function(faculty = "Математички факултет") {
paste("Марко иде на", faculty)
}
my_faculty("Економски факултет")## [1] "Марко иде на Економски факултет"
## [1] "Марко иде на Математички факултет"
- Функција која црта два графика \(y(x)\) и \(x(y)\) у произвољној боји.
# colors() - ispisuje sve postojece boje u R-u
nacrtaj <- function(v1, v2){
par(mfrow = c(1,2))
plot(v1, v2, col="turquoise")
plot(v2, v1, col="turquoise")
par(mfrow = c(1,1))
}
nacrtaj(sample(1:1000,100), sample(1:1000,100))- Функција која има више повратних вредности.
mean_median <- function(vector){
mean <- mean(vector)
median <- median(vector)
return(c(mean, median))
}
print(mean_median(c(1, 1, 1, 2, 3)))## [1] 1.6 1.0
Rectangle = function(length, width){
area = length * width
perimeter = 2 * (length + width)
result = list("Area" = area, "Perimeter" = perimeter)
return(result)
}
resultList = Rectangle(2, 3)
print(resultList["Area"])## $Area
## [1] 6
## $Perimeter
## [1] 10
- Позивање једне функције у телу друге функције.
radius_from_diameter <- function(d){
d/2
}
circumference <- function(r){
2*pi*r
}
print(circumference(radius_from_diameter(4)))## [1] 12.56637
sum_circle_ares <- function(r1, r2, r3){
circle_area <- function(r){
pi*r^2
}
circle_area(r1) + circle_area(r2) + circle_area(r3)
}
print(sum_circle_ares(1, 2, 3))## [1] 43.9823
Приметимо да је функција circle_area дефинисана у телу
функције sum_circle_ares и видљива је само локално у тој
функцији.
print(circle_area(10))
Error in circle_area(10): could not find function "circle_area"
Traceback:
1. print(circle_area(10))
- Могуће је дефинисати и рекурзивне функције, тј. функције које позивају саму себе.
tri_recursion <- function(k) {
if (k > 0) {
result <- k + tri_recursion(k - 1)
print(result)
} else {
result = 0
return(result)
}
}
tri_recursion(6)## [1] 1
## [1] 3
## [1] 6
## [1] 10
## [1] 15
## [1] 21
- Глобално и локално дефинисане променљиве и функције.
## [1] "R is awesome"
txt <- "global variable"
my_function <- function() {
txt = "fantastic"
paste("R is", txt)
}
my_function()## [1] "R is fantastic"
## [1] "global variable"
IF наредбе и FOR, WHILE, REPEAT петље
Било која целина или блок наредби може се издвојити заградама \(\{ \}\). Ако у конзоли пређемо у нови ред, а траје блок, појавиће се + да то означи.
IF наредба
- Постоје два основна типа логичог гранања:
if (expr_1) expr_2if (expr_1) expr_2 else expr_3при чему изразexpr_1мора имати логичку вредност.
## [1] "Positive number"
## [1] "Negative number"
- Претходно је могуће записати компактно у једној линији. Наредбе могу да буду и сложене, само би се онда ограничиле са \(\{\}\).
if(x >= 0) print("Non-negative number") else print("Negative number")
## [1] 6
IF ELSE лествице
x <- 0
if (x < 0) {
print("Negative number")
} else if (x > 0) {
print("Positive number")
} else
print("Zero")## [1] "Zero"
x <- 20
if (x > 0) {
if (x %% 2 == 0) {
print("x је позитиван паран број")
} else {
print("x је позитиван непаран број")
}
} else {
if (x %% 2 == 0) {
print("x је негативан паран број")
} else {
print("x је негативан непаран број")
}
}## [1] "x је позитиван паран број"
IFELSE наредба
- Функција
ifelseпредставља векторску репрезентацијуif elseгранања:ifelse(vector_with_condition, value_if_TRUE, value_if_FALSE).
## [1] TRUE TRUE TRUE TRUE FALSE
x <- c("male", "male", "female", "male", "female")
y <- c(10, 14, 80, 56, 27)
ifelse (x == "male", ifelse(y > 18, "Adult male", "Underage male"),
ifelse(y > 18, "Adult female", "Underage female"))## [1] "Underage male" "Underage male" "Adult female" "Adult male"
## [5] "Adult female"
## [1] 1 0 1 1 0
FOR петља
for(i in start:finish) {statement}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
- Пролазак бројача кроз листу, а не вектор.
## [1] "Color: green"
## [1] "Color: blue"
## [1] "Color: red"
- Цртање графика помоћу for петље.
- Двострука
forпетља.
## [,1] [,2] [,3] [,4]
## [1,] 2 3 4 5
## [2,] 3 4 5 6
## [3,] 4 5 6 7
## [4,] 5 6 7 8
## [5,] 6 7 8 9
- Пример оцењивања расподеле узорачке средњих вредности на основу хистограма.
set.seed(1) # Setting a seed for reproducibility
rep <- 50000 # Number of repetitions
n <- 2 # Number of points
Mean <- numeric(rep)
for (i in 1:rep) {
x <- runif(n)
Mean[i] <- mean(x)
}
hist(Mean, breaks = 40, main = paste("n = ", n))Next и break наредбе
## [1] 1
## [1] 2
## [1] 4
## [1] 5
WHILE петља
while (logic_condition) {statement}
- Одређивање факторијела задатог броја.
factorialR <- function(x) {
if (x == 0) {
res <- 1
} else {
res <- x
while(x > 1){
res <- (x - 1) * res
x <- x - 1
}
}
return(res)
}
factorialR(8)## [1] 40320
## [1] 1
- Одређивање првог природног броја чији квадрат је већи од задате границе.
REPEAT наредба
Садржи наредбе које се извршавају, као и услов за излазак из петље, иначе имамо бесконачну петљу!
repeat{statement if (logic_condition) break}
## [1] 5
- Функција која из базе
sleepбрише елементе код којих је параметарextraмањи од задатог броја.
## extra group ID
## 1 0.7 1 1
## 2 -1.6 1 2
## 3 -0.2 1 3
## 4 -1.2 1 4
## 5 -0.1 1 5
## 6 3.4 1 6
## 7 3.7 1 7
## 8 0.8 1 8
## 9 0.0 1 9
## 10 2.0 1 10
## 11 1.9 2 1
## 12 0.8 2 2
## 13 1.1 2 3
## 14 0.1 2 4
## 15 -0.1 2 5
## 16 4.4 2 6
## 17 5.5 2 7
## 18 1.6 2 8
## 19 4.6 2 9
## 20 3.4 2 10
## extra group ID
## 6 3.4 1 6
## 7 3.7 1 7
## 16 4.4 2 6
## 17 5.5 2 7
## 19 4.6 2 9
## 20 3.4 2 10
Ако хоћемо да нам функција врати више ствари, на пример, хоћемо као претходно, али и да враћа број обрисаних елемената. Потребно је да функција врати две ставке различитог типа, па морамо направити листу.
brisi1 <- function(x){
return (list(sleep[sleep$extra >= x,], nrow(sleep[sleep$extra < x,])))
}
brisi1(2.1)## [[1]]
## extra group ID
## 6 3.4 1 6
## 7 3.7 1 7
## 16 4.4 2 6
## 17 5.5 2 7
## 19 4.6 2 9
## 20 3.4 2 10
##
## [[2]]
## [1] 14
*apply функције
Фамилија функција *apply са функцијама
apply, sapply и lapply чини
основу функционалног програмирања у R-у. У пиитању су
функције које служе за пресликавање елемената (вектора/матрица/листи) у
нове елементе применом једне исте функције на сваки елемент.
apply(X, # Array, matrix or data frame
MARGIN, # 1: rows, 2: columns, c(1, 2): rows and columns
FUN, # Function to be applied
...) # Additional arguments to FUN
Функција sapply
Позив функције: sapply(v, f), где је v
вектор, матрица или листа, а f функција коју треба
применити на сваки елемент од v.
sapply(X, # Vector, list or expression object
FUN, # Function to be applied
..., # Additional arguments to be passed to FUN
simplify = TRUE, # If FALSE returns a list. If "array" returns an array if possible
USE.NAMES = TRUE) # If TRUE and if X is a character vector, uses the names of X
Дакле, sapply примењује дату функцију на сваки елемент
датог вектра/матрице/листе и враћа резултујући вектор. Напоменимо да
увек покушава да врати вектор, а уколико то није могуће враћа листу.
- Кореновање сваког члана вектора.
## [1] 1.000000 1.414214 1.732051 2.000000
## [1] 1.000000 1.414214 1.732051 2.000000
## [1] 1.000000 1.414214 1.732051 2.000000
Аргумент функције не мора бити вектор, може бити и листа, али као излазну вредност опет добијамо вектор.
## A B C
## 5 15 1
- За листу матрица желимо да одредимо суму свих вредности у матрици.
matrix_list <- list(diag(5), diag(7), matrix(1:10, nrow = 2))
matrix_sums <- sapply(matrix_list, sum)
matrix_sums## [1] 5 7 55
Ово је исто што и
## [1] 5 7 55
Уколико се примењује вишедимензиона функција, функција
sapply може да врати и матрицу.
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 2 3 4 5
## [2,] 1 4 9 16 25
Свака колона је један резултат примењене функције. Прва врста је \(k\), а друга је \(k^2\).
- Функцију
sapplyможемо применити и на базе података.
## a b c
## 1 1 4 14
## 2 3 4 15
## 3 7 6 11
## 4 12 7 10
## 5 9 8 6
## a b c
## 6.4 5.8 11.2
## a b c
## [1,] 2 8 28
## [2,] 6 8 30
## [3,] 14 12 22
## [4,] 24 14 20
## [5,] 18 16 12
- Можемо користити функцију
sapplyза цртање графика.
plot(rnorm(10), ylim = c(-6, 6))
nlines <- 5
invisible(sapply(1:nlines, function(i) lines(-i:i, col = i, lwd = 3)))Функција lapply
Користи се на исти начин као и функција sapply, само што
као резултат враћа листу, а не вектор. Дакле, када не очекујемо да
резултат буде увек истог типа и димензије, већ желимо да излаз буде
листа, користимо функцију lapply.
lapply(X, # List or vector
FUN, # Function to be applied
...) # Additional arguments to be passed to FUN
- Примена на елементе вектора.
## [[1]]
## [1] 3.464102
##
## [[2]]
## [1] 4.242641
##
## [[3]]
## [1] 2.44949
- За неки вектор направимо листу дијагоналних матрица одговарајуће димензије.
## [[1]]
## [,1]
## [1,] 1
##
## [[2]]
## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 0 1 0
## [3,] 0 0 1
##
## [[3]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 0 0 0 0
## [2,] 0 1 0 0 0
## [3,] 0 0 1 0 0
## [4,] 0 0 0 1 0
## [5,] 0 0 0 0 1
Исти резултат преко for петље:
## [[1]]
## [,1]
## [1,] 1
##
## [[2]]
## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 0 1 0
## [3,] 0 0 1
##
## [[3]]
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 0 0 0 0
## [2,] 0 1 0 0 0
## [3,] 0 0 1 0 0
## [4,] 0 0 0 1 0
## [5,] 0 0 0 0 1
- Функција
lapplyса додатним аргументима.
c <- list(A = c(56, 12, 57, 24), B = c(89, 12, 64, 18, 65, 76))
lapply(c, # List
quantile, # Applied function
probs = c(0.25, 0.5, 0.75)) # Additional argument of the quantile function## $A
## 25% 50% 75%
## 21.00 40.00 56.25
##
## $B
## 25% 50% 75%
## 29.50 64.50 73.25
lapply или sapply
## [[1]]
## [1] 2
##
## [[2]]
## [1] 3
##
## [[3]]
## [1] 4
## [1] 2 3 4
## [[1]]
## [1] 2
##
## [[2]]
## [1] 3
##
## [[3]]
## [1] 4
## [[1]]
## [1] 2
##
## [[2]]
## [1] 3
##
## [[3]]
## [1] 4
## [1] 2 3 4
## [1] 2 3 4
Функција apply
Функција apply се користи када имамо вишедимензиони улаз
(нпр. матрица или база податакa), а желимо да применимо неку функцију по
колонама или по врстама.
Функција се позива са apply(mat, dim, f), где је
mat матрица или база података, dim је
димензија по којој примењујемо функцију (1 је за врста, а 2 за колоне),
a f je функција коју примењујемо на сваку врсту или
колону.
apply(X, # Array, matrix or data frame
MARGIN, # 1: rows, 2: columns, c(1, 2): rows and columns
FUN, # Function to be applied
...) # Additional arguments to FUN
- Збир елемената у свакој колони неке матрице.
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
## [1] 6 15 24 33
Ово је еквивалентно са
## [1] 6 15 24 33
- Ако желимо просек по врстама
## [1] 5.5 6.5 7.5
Што је еквивалентно са
## [1] 5.5 6.5 7.5
Резултат не мора бити вектор, можемо вратити резултат позива функције
summary на сваку колону базе и добијамо матрицу.
## speed dist
## 1 4 2
## 2 4 10
## 3 7 4
## 4 7 22
## 5 8 16
## 6 9 10
## speed dist
## Min. 4.0 2.00
## 1st Qu. 12.0 26.00
## Median 15.0 36.00
## Mean 15.4 42.98
## 3rd Qu. 19.0 56.00
## Max. 25.0 120.00
- Примена функције на сваки елемент базе.
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] -98 -78 -58 -38 -18 2 22 42 62 82
## [2,] -96 -76 -56 -36 -16 4 24 44 64 84
## [3,] -94 -74 -54 -34 -14 6 26 46 66 86
## [4,] -92 -72 -52 -32 -12 8 28 48 68 88
## [5,] -90 -70 -50 -30 -10 10 30 50 70 90
## [6,] -88 -68 -48 -28 -8 12 32 52 72 92
## [7,] -86 -66 -46 -26 -6 14 34 54 74 94
## [8,] -84 -64 -44 -24 -4 16 36 56 76 96
## [9,] -82 -62 -42 -22 -2 18 38 58 78 98
## [10,] -80 -60 -40 -20 0 20 40 60 80 100
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 2 2 2 2 2 2 2 2 2 2
## [2,] 4 4 4 4 4 4 4 4 4 4
## [3,] 6 6 6 6 6 6 6 6 6 6
## [4,] 8 8 8 8 8 8 8 8 8 8
## [5,] 0 0 0 0 0 0 0 0 0 0
## [6,] 2 2 2 2 2 2 2 2 2 2
## [7,] 4 4 4 4 4 4 4 4 4 4
## [8,] 6 6 6 6 6 6 6 6 6 6
## [9,] 8 8 8 8 8 8 8 8 8 8
## [10,] 0 0 0 0 0 0 0 0 0 0
- Стандардизација колона базе података
Извршимо стандардизацију колоне базе података применом функције
apply. Применићемо следећу трансформацију \(\frac{X-m}{\sigma}\) да бисмо добили
случајну величину са очекивањем 0 и дисперзијом 1.
## speed dist
## [1,] -2.155969 -1.5902596
## [2,] -2.155969 -1.2798136
## [3,] -1.588609 -1.5126481
## [4,] -1.588609 -0.8141446
## [5,] -1.399489 -1.0469791
## [6,] -1.210369 -1.2798136
Израчунајмо просек и дисперзију оригиналних и скалираних података.
## speed dist
## [1,] 15.40000 42.9800
## [2,] 27.95918 664.0608
## speed dist
## [1,] 0 0
## [2,] 1 1
Дакле, очекивано, скалирани подаци су такви да су просек и дисперзија сваке колоне редом 0 и 1.
Задатак за вежбу
- Имплементирати функцију
Removeкоја из базе iris брише елементе код којих је параметар Sepal.Length мањи од средње вредности и параметар Sepal.Width мањи од медијане вредности у посматраној колони.
Remove <- function(){
Mean <- mean(iris$Sepal.Length)
Median <- median(iris$Sepal.Width)
condition <- iris$Sepal.Length >= Mean & iris$Sepal.Width >= Median
return(iris[condition,])
}
Remove()## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 51 7.0 3.2 4.7 1.4 versicolor
## 52 6.4 3.2 4.5 1.5 versicolor
## 53 6.9 3.1 4.9 1.5 versicolor
## 57 6.3 3.3 4.7 1.6 versicolor
## 62 5.9 3.0 4.2 1.5 versicolor
## 66 6.7 3.1 4.4 1.4 versicolor
## 71 5.9 3.2 4.8 1.8 versicolor
## 76 6.6 3.0 4.4 1.4 versicolor
## 78 6.7 3.0 5.0 1.7 versicolor
## 86 6.0 3.4 4.5 1.6 versicolor
## 87 6.7 3.1 4.7 1.5 versicolor
## 92 6.1 3.0 4.6 1.4 versicolor
## 101 6.3 3.3 6.0 2.5 virginica
## 103 7.1 3.0 5.9 2.1 virginica
## 105 6.5 3.0 5.8 2.2 virginica
## 106 7.6 3.0 6.6 2.1 virginica
## 110 7.2 3.6 6.1 2.5 virginica
## 111 6.5 3.2 5.1 2.0 virginica
## 113 6.8 3.0 5.5 2.1 virginica
## 116 6.4 3.2 5.3 2.3 virginica
## 117 6.5 3.0 5.5 1.8 virginica
## 118 7.7 3.8 6.7 2.2 virginica
## 121 6.9 3.2 5.7 2.3 virginica
## 125 6.7 3.3 5.7 2.1 virginica
## 126 7.2 3.2 6.0 1.8 virginica
## 128 6.1 3.0 4.9 1.8 virginica
## 130 7.2 3.0 5.8 1.6 virginica
## 132 7.9 3.8 6.4 2.0 virginica
## 136 7.7 3.0 6.1 2.3 virginica
## 137 6.3 3.4 5.6 2.4 virginica
## 138 6.4 3.1 5.5 1.8 virginica
## 139 6.0 3.0 4.8 1.8 virginica
## 140 6.9 3.1 5.4 2.1 virginica
## 141 6.7 3.1 5.6 2.4 virginica
## 142 6.9 3.1 5.1 2.3 virginica
## 144 6.8 3.2 5.9 2.3 virginica
## 145 6.7 3.3 5.7 2.5 virginica
## 146 6.7 3.0 5.2 2.3 virginica
## 148 6.5 3.0 5.2 2.0 virginica
## 149 6.2 3.4 5.4 2.3 virginica
## 150 5.9 3.0 5.1 1.8 virginica
- Одредити средњу вредност и стандардну девијацију параметара Petal.Length и Petal.Width, а затим стандардизовати (нумеричке) колоне базе iris.
## Petal.Length Petal.Width
## Mean 3.758000 1.1993333
## SD 1.765298 0.7622377
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## [1,] -0.8976739 1.01560199 -1.335752 -1.311052
## [2,] -1.1392005 -0.13153881 -1.335752 -1.311052
## [3,] -1.3807271 0.32731751 -1.392399 -1.311052
## [4,] -1.5014904 0.09788935 -1.279104 -1.311052
## [5,] -1.0184372 1.24503015 -1.335752 -1.311052
## [6,] -0.5353840 1.93331463 -1.165809 -1.048667
- Одредити 25%, 50% и 75% квартил за сваку (нумеричку) колону базе iris.
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## 25% 5.1 2.8 1.60 0.3
## 50% 5.8 3.0 4.35 1.3
## 75% 6.4 3.3 5.10 1.8