Основы программирования: авторские функции

images
Во многих случаях (когда необходимо решить специфическую задачу) можно обойтись написанием скрипта (здесь имеется ввиду программный код для конкретного случая) по типу того, который приведен в предыдущей статье (создание фреймов данных для каждого года и запись их в список). Маловероятно, что такие скрипты понадобятся в дальнешем. Поэтому их специфическая адаптация для других ситуаций не требуется.
Вместе с тем, возникают и ситуации, когда необходимо написать такой программный код, который бы решал одну и ту же задачу, возникающую часто и требующую учета изменяющихся ключевых данных. По этой причине, в процессе работы можно применять не только уже имеющиеся функции, но и создавать свои собственные. Такие авторские функции позволяют использовать уже имеющиеся в R функции, условные операторы, циклы, списки и многое другое. Для многих языков программирование функциональное программирование является одной из основ. В случае R (если мы говорим про анализ данных) многие задачи уже реализованы как в базовой версии, так и виде расширений. Несмотря на это, функциональное программирование в R также является важным дополнением, существенно расширяющим возможности исследователя.
Создание авторской функции
Для создания авторской функции используется функция function(), состоящая из двух компонентов: а) тех аргументов, которые принимает функция (входящие данные; в некоторых случаях они могут и не понадобиться); б) синтаксис, который при использовании входящих данных решает задачи исследователя; если синтаксис включает единственное выражение, то вводится в той же строке, где объявляется функция, в других случаях он размещается в фигурных скобках.
Рассмотрим элементарные примеры (исключительно в дидактических целях):
1
2
3
4
5
6
7
8
9
  > fun1 <- function(x1, x2) print(x1+x2)
  > fun1(1, 2)
  [1] 3
  > fun2 <- function(x1, x2) {
      x3 <- x1+x2
      print(x3/x2)
    }
  > fun2(1, 2)
  [1] 1.5
Первая функция (fun1()) необходима для того, чтобы найти сумму двух значений. Сначала мы указываем, что функция примет два значения - x1 и x2, после чего прописываем действие с ними - вывод на экран их суммы с помощью функции print(). Во второй строке синтаксиса мы используем функцию. Для этого необходимо ввести ее имя и указать в скобках те значения, которыми являются x1 и x2. Поскольку x1 мы принимаем за "1", а х2 - за "2", итогом будет "3".
Следующая функция включает более одного выражения, поэтому ее синтаксис прописан в фигурных скобках. Как и в предыдущем случае она принимает два значения - x1 и x2. Далее эти значения складываются и записываются в x3, после чего с помощью функции print() на экран выводится результат от деления х3 на х2. Использовав те же аргументы, что и в первой функции, мы получим "1,5".
Одной из особенностей авторских функций является то, что все объекты, которыми оперирует функция являются внутренними, то есть они недоступны за пределами функции. Поэтому в случаях, когда необходимо получить определенный результат "на выходе", используется функция return(). Для того, чтобы понять как она работает, изменим вторую авторскую функцию (fun2()):
10
11
12
13
14
15
16
  > fun2 <- function(x1, x2) {
      x3 <- x1+x2
      return(x3/x2)
    }
  > result <- fun2(1, 2)
  > result
  [1] 1.5
Теперь функция вместо того, чтобы выводить x3/x2 с помощью print(), она возвращает это выражение с помощью return(). И это будет тот результат, который мы можем передать (записать) какому-либо объекту. В нашем случае мы записываем результат выполнения функции в объект result. После этого мы выводи его на экран. Авторская функция может возвращать самые разные объекты (скаляры, векторы, списки и так далее).
Теперь рассмотрим более содержательные примеры.
Авторская функция для расчета коэффициента изменчивости категорий (IQV)

Для чего нужен коэффициент изменчивости категорий, какова его формула и пример ее использования вы можете посмотреть здесь. Как видно, для расчета IQV необходимо знать количество категорий переменной, частоту каждой категории и количество наблюдений (которое, впрочем, является суммой частот). Следовательно, функция будет включать три аргумента (хотя можно обойтись и меньшим числом). Касательно синтаксиса функции: поскольку формула представлена в виде обыкновенной дроби, постольку синтаксис будет находить числитель, знаменатель и уже потом результат деления.
Итак:
17
18
19
20
21
22
23
24
25
26
27
  > IQV <- function(f_vector,k,N) {
      numerator <- k*(N^2 - sum(f_vector^2))
      denominator <- N^2*(k-1)
      iqv <- numerator/denominator
      return(iqv)
    }
  > freq <- c(30,20,10)
  > kat <- length(freq)
  > total <- sum(freq)
  > IQV(freq,kat,total)
  [1] 0.9166667
После создания функции, готовятся данные, соответствующие одномерному распределению и его параметрам, необходимым для вычисления IQV. Далее эти данные используются в качестве аргументов функции. Как видно, для реализации этой функции достаточно всего одного аргумента - f_vector, из которого могут быть выведены все остальные.

Авторская функция для расчета количества эффективных партий
В одном из своих недавних исследований меня интересовали три электоральных показателя по всем странам мира: а) количество всех партий, прошедших в парламент страны; б) количество релевантных партий в парламенте (более 3%); в) количество эффективных партий.
Последний показатель является в некотором смысле абстрактной величиной, которая рассчитывается по следующей формуле:
Stacks Image 5907
здесь "p" обозначает пропорцию мест в парламенте i-той партии.
Осуществлять расчет в ручную или с помощью Excel было неудобно. Поэтому я написал функцию, которая бы сообщала мне четыре показателя (кроме уже указанных - общее количество мест в парламенте). При этом пришлось использовать цикл, условный оператор, список и ряд уже имеющихся в R функций:
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  > schitalka <- function(seats) {
      forEachParty <- list() # создаем пустой список, он понадобится
      relevant <- 0 # приравниваем количество релевантных партий к 0
      totalSeats <- sum(seats) # находим общее количество мест в парламенте
      for (i in 1:length(seats)) {
        p2 <- (seats[i] / totalSeats)^2 # для каждой партии находим "р" в квадрате
        forEachParty[[i]] <- p2 # записываем предыдущую величину в список
        if (seats[i] / sum(seats) > 0.03) relevant <- relevant+1 # если количество мест партии превышает 3% увеличиваем relevant на 1
      }
      numberOfEP <- 1 / sum(as.vector(forEachParty, mode="numeric")) # находим количество эффективных партий
      cat("к-во партий             :", length(seats), "\n") # здесь и далее выводим показатели на экран
      cat("к-во релевантных партий :", relevant, "\n")
      cat("к-во эффективных партий :", numberOfEP, "\n")
      cat("общее количество мест   :", totalSeats, "\n")
    }
  > schitalka(c(12,8,1)) # запускаем функцию, в качестве аргумента используется количество мест, полученных каждой партией в парламенте
  к-во партий             : 3 
  к-во релевантных партий : 3 
  к-во эффективных партий : 2.110048 
  общее количество мест   : 21 

статью подготовил кандидат социологических наук Сергей Дембицкий

Data science (3)
Europe (2)
Geopolitics (2)
Infographics (1)
R (26)
Russia (2)
SPSS (2)
Ukraine (2)
Акционализм (1)
Анализ данных (27)
Аномия (1)
Выборка (1)
Выступления (3)
Геополитика (12)
Гражданское общество (2)
Демократизация (1)
Европа (4)
Интернет ресурсы (1)
Инфографика (8)
Исследовательские дизайны (1)
Историческая социология (10)
История социологии (5)
Киберспорт (1)
Книги (7)
Массивы (3)
Методология социальных исследований (1)
Методология социологических исследований (2)
Научная жизнь (3)
Новости (6)
Обратная связь (1)
Персоналии (3)
Православные конфессии в Украине (1)
Президентская власть (1)
Психологический дистресс (18)
Психология (5)
Публицистика (2)
Революция (1)
Результаты исследований (28)
Религия (3)
Россия (2)
Согласование концептов (4)
Социальная гетерогенность (1)
Социальная работа (1)
Социологическая теория (6)
Социологические тесты (1)
Социологическое образование (5)
Теория конфликта (2)
Теория социального измерения (8)
Украина (9)
Учебные планы (2)
Философия (1)
Шкалирование (36)
Экономика (1)
Эмпирическая социология (46)

free counters
Яндекс.Метрика