Мы уже встречали много различных встроенных функций. Давайте вспомним некоторые из них:
cos(x)
- косинус числа xround(x, n)
- округление числа x до n знака после запятойfactorial(n)
- факториал числа nsum(x)
- сумма значений массива xДля использования функции мы пишем ее название, ставим круглые скобки и в них перечисляем аргументы через запятую.
Предположим у нас есть 3 массива. И нам нужно найти сумму каждого из них. Не зная, что такое функция, мы бы сделали следующим образом.
m1 <- 1:5
m2 <- 3:6
m3 <- c(-10,0,9)
s1 <- 0
for(i in 1:length(m1)){
s1 <- s1 + m1[i]
}
s2 <- 0
for(i in 1:length(m2)){
s2 <- s2 + m2[i]
}
s3 <- 0
for(i in 1:length(m3)){
s3 <- s3 + m3[i]
}
print(s1)
## [1] 15
print(s2)
## [1] 18
print(s3)
## [1] -1
Если представить, что таких массивов будет больше или мы будем находить не сумму, а что-то другое (где код будет гораздо больше), то возникает проблема: код занимает очень много места, хотя производится одна и та же операция, но с разными входными данными. Для решения данной проблемы была придумана функция.
SUM <- function(x){
s <- 0
for(i in 1:length(x)){
s <- s + x[i]
}
return(s)
}
SUM(m1)
## [1] 15
SUM(m2)
## [1] 18
SUM(m3)
## [1] -1
Код значительно уменьшился. Не бойтесь, что не понимаете как мы сделали собственную функцию. Позже мы разберем все на более простых примерах. А сейчас разберем общий алгоритм создания функций.
function()
, тем самым давая понять R, что вы создаете функцию.return()
, где в круглых скобках записать объект (переменная, массив, матрица или еще что-то), что вы хотите вывести. Например в задаче с суммой массива, мы выводим переменную, которая отвечает за сумму. По сути return()
это примерно тоже самое, что и print()
, но только print()
выводит что-то на экран, а return()
“выкидывает” ответ из функции.При создании любой функции важно понять, какие аргументы идут на вход и что идет на выход. Это можно изобразить на черном ящике.
Реализуем эту функцию. И запустим ее для аргмументов 5 и 7.
## [1] 35
Попробуем сделать функцию, которая выводит квадрат числа.
## [1] 25
А теперь попробуем сделать функцию, которая считает квадрат или куб числа, в зависимости от какого-то другого аргумента.
sq_or_cu <- function(x,y){
if(y == 'Квадрат'){
l <- x^2
return(l)
} else {
l <- x^3
return(l)
}
}
sq_or_cu(3,y = 'Куб')
## [1] 27
## [1] 9
Как видим, можно использовать несколько return
.
Замечание: Когда вы пишите достаточно большой код, а потом еще оборачиваете это в функцию, то очень легко запутаться с фигурными скобками, так как их становится очень много. Чтобы этого избежать, всегда используете правила написания красивого кода: делайте вложенные отступы, закрывающие скобки пишите на отдельных строках, делайте код приятным на глаз. Также можно навести курсор мыши на интересующую вас скобку и R покажет вам, с какой другой скобкой она связана.
У многих функций, есть дефолтные параметры. Они нужны, чтобы уменьшить написание входных переменных функции. Если вы чаще используете возведение в квадрат, и только иногда в куб, то стоит поставить аргументу значение по умолчанию. Это делается при перечислении аргументов. Там можно поставить знак равно и ввести аргумент по умолачанию.
sq_or_cu <- function(x, y = 'Квадрат'){
if(y == 'Квадрат'){
l <- x^2
return(l)
} else {
l <- x^3
return(l)
}
}
sq_or_cu(3)
## [1] 9
## [1] 27
Замечание: Мы с вами уже сталкивались с аргументами по умолчанию в встроенных функциях. Например, функция round
имеет аргумент digits
, который по умолчанию равен 0, либо функция log
имеет по умолчанию основание exp(1)
. Если же какому-либо аргументу не присвоить значение по умолчанию внутри функции, то тогда если вы его не передадите в функцию, она работать не будет!
Внутри каждой функции обычно используются какие-то дополнительные переменные. Но их значение используется только внутри функции, поэтому такие переменные называются локальными. То есть эти переменные не остаются в памяти. Переменные, которые мы видим в правом верхнем окошке являются глобальными. К локальным переменным нельзя обращаться за пределами функций.
## Error in eval(expr, envir, enclos): объект 'l' не найден
При запуске предыдущей функции мы не видим переменную l в правом верхнем углу. Если мы хотим сделать переменную глобальной, нужно изменить знак присвоения на <<-
.
## [1] 25
Теперь можно увидеть переменную l в правом верхнем углу.
Поработаем теперь с return
. Важно, что должна выводить функция.
## [1] 25
## [1] 1
Выводить можно несколько чисел, с помощью массива. К этому массиву можно потом обращаться.
abc <- function(x){
a <- x*5
b <- x/5
c <- x+5
return(c(a,b,c))
}
w <- abc(5)
w[1] # a
## [1] 25
w[2] # b
## [1] 1
w[3] # c
## [1] 10
После написания return
функция останавливает работу и выходит из нее. Например попробуем вывести на экран сумму чисел после return
. Это не сработает, так как строчка print(a + b + c)
уже не будет запускаться. Функция прекратила свою работу ранее и вывела массив этих значений.
## [1] 25 1 10
Прежде чем написать функцию, попробуйте просто написать код внутри нее и проверить работает ли он, а уже потом сделать его в виде функции.
Например, код для вычисления факториала.
## [1] 120
Тут можно быстро проверить, все ли работает корректно. А уже потом оформить это в виде функции. На вход подается число n
. На выходе k
.
Теперь поговорим про рекурсию. Рекурсия - это функция, которая использует саму себя.