Книга: Байесовская статистика: Star Wars, LEGO, резиновые уточки и многое другое
Назад: Приложения
Дальше: Б. Математический минимум

А. Краткое введение в язык R

В этой книге для выполнения сложной вычислительной работы используется язык R, который специализируется на статистике и науке о данных. Если у вас нет опыта работы с R или вообще с программированием, не беспокойтесь — это приложение поможет вам начать работу.

R и RStudio

Для запуска примеров кода в этой книге необходимо установить R на компьютер. Для этого перейдите по ссылке https://cran.rstudio.com/ и следуйте инструкциям по установке для используемой операционной системы.

После установки R также нужно установить RStudio, интегрированную среду разработки (IDE), которая делает запуск проектов R чрезвычайно простым. Загрузите и установите RStudio с сайта www.rstudio.com/products/rstudio/download/.

При открытии RStudio вас должны встретить несколько панелей (рис. A.1).

Самая важная панель — большая в середине, называемая консолью. В консоли можно ввести любой из примеров кода из книги и запустить его, просто нажав клавишу Enter. Консоль сразу запускает весь код, который вы вводите, что затрудняет отслеживание написанного кода.

A_01.tif 

Рис. A.1. Просмотр консоли в RStudio

Чтобы писать программы, которые можно сохранить и вернуться к ним, нужно поместить свой код в сценарий R, который представляет собой текстовый файл. Его можно загрузить в консоль позже. R — чрезвычайно интерактивный язык программирования, поэтому вместо того чтобы думать о консоли как о месте, где можно тестировать код, следует представлять сценарии R как способ быстрой загрузки инструментов, которые можно использовать в консоли.

Создание сценария в R

Чтобы создать сценарий в R, перейдите к FileNew FileR Script в RStudio. Появится новая пустая панель в левом верхнем углу (рис. A.2).

На этой панели вы можете ввести код и сохранить его в виде файла. Чтобы запустить код, просто нажмите кнопку Source в правом верхнем углу панели или запустите отдельные строки, нажав кнопку Run. Кнопка Source автоматически загрузит ваш файл в консоль, как если бы вы его там напечатали.

A_02.tif 

Рис. A.2. Создание сценария в R

Основные понятия R

Мы будем использовать R в качестве продвинутого калькулятора, а это значит, что требуется понять только основы, чтобы разобраться с проблемами и самостоятельно расширить примеры из этой книги.

Типы данных

Все языки программирования имеют различные типы данных, которые можно использовать для разных целей и по-разному манипулировать ими. R включает в себя большое разнообразие типов и структур данных, но в этой книге мы будем использовать только небольшое их количество.

Числа с плавающей точкой

Числа, которые мы используем в R, имеют тип double (сокращение от «числа с плавающей точкой двойной точности», double-precision floating-point, которое является наиболее распространенным способом представления десятичных чисел в компьютере). Число с плавающей точкой является типом по умолчанию для представления десятичных чисел. Если не указано иное, все числа, которые вы вводите в консоль, имеют тип double.

Мы можем манипулировать такими числами с помощью стандартных математических операций. Например, можно сложить два числа с помощью оператора +. Попробуйте воспроизвести это в консоли:

> 5 + 2

[1] 7

С помощью оператора / можно разделить любые числа, что даст десятичный результат:

> 5/2

[1] 2.5

Можно умножить значения с помощью оператора *:

> 5 * 2

[1] 10

И возвести значение в степень, используя оператор ^. Например, 52 это:

> 5^2

[1] 25

Также можно добавить перед числом знак «минус», чтобы сделать его отрицательным:

> 5 — -2

[1] 7

И еще можно использовать экспоненциальную запись с e+. Таким образом, 5 × 102 — это просто:

> 5e+2

[1] 500

Если мы используем e-, то получаем тот же результат, что и 5 × 10–2:

> 5e-2

[1] 0.05

Это полезно знать, потому что иногда R возвращает результат в экспоненциальной записи, если он слишком большой:

> 5*10^20

[1] 5e+20

Строки

Еще один важный тип в R — это строка (string), представляющая собой группу используемых символов для отображения текста. В R мы заключаем строку в кавычки, например:

> "hello"

[1] "hello"

Обратите внимание, что если вы помещаете число в строку, это число нельзя использовать в обычных числовых операциях, поскольку строки и числа — это разные типы. Например:

> "2" + 2

Error in "2" + 2 : non-numeric argument to binary operator

Мы не будем широко использовать строки в этой книге. В первую очередь они потребуются для передачи аргументов функциям и для обозначения графиков. Но важно помнить о них, если вы используете текст.

Логические типы

Логические, или бинарные, типы представляют истинные или ложные значения, выраженные кодами TRUE и FALSE. Обратите внимание, что TRUE и FALSE не являются строками — они не заключены в кавычки и пишутся заглавными буквами. (R также позволяет вам просто использовать T или F вместо записи полных слов.)

Логические типы можно комбинировать с символами & («и») и | («или») для выполнения основных логических операций. Например, если мы хотим узнать, может ли что-то быть одновременно истинным и ложным, то можем ввести:

> TRUE & FALSE

R вернет:

[1] FALSE

сообщая нам, что значение не может быть одновременно истиной и ложью. Но как насчет истины или лжи?

> TRUE | FALSE

[1] TRUE

Как и строки, логические значения будут в основном использоваться для предоставления аргументов функциям, которые мы будем использовать, или в качестве результатов сравнения двух разных значений.

Отсутствующие значения

В практической статистике и data science в данных часто отсутствуют некоторые значения. Например, есть данные о температуре для утра и полдня каждого дня в течение месяца, но однажды что-то дает сбой и вы обнаруживаете, что не хватает утренней температуры. Поскольку отсутствующие значения встречаются очень часто, R имеет особый способ их представления: значение NA. Важно иметь способ обрабатывать отсутствующие значения, потому что они могут означать очень разные вещи в разных контекстах. Например, при измерении количества осадков отсутствующее значение может означать, что в датчике не было дождя, или это может означать, что было много дождей, но в ту ночь температура была ниже нуля, что привело к поломке датчика и утечке воды. В первом случае мы могли бы считать, что отсутствующие значения означают 0, но во втором случае неясно, каким должно быть значение. Хранение отсутствующих значений отдельно от других значений заставляет нас учитывать эти различия. Чтобы подсказать нам, каковы наши отсутствующие значения каждый раз, когда мы пытаемся их использовать, R будет выводить NA для любой операции, используя отсутствующее значение:

> NA + 2

[1] NA

Как мы увидим чуть позже, разные функции в R могут обрабатывать отсутствующие значения различными способами, но не нужно беспокоиться об отсутствующих значениях для примеров R, используемых в этой книге.

Векторы

Почти каждый язык программирования содержит определенные функции, которые делают его уникальным и подходящим для решения задач в своей области. Особенность R в том, что это векторный язык. Вектор — это список значений, и все, что делает R, — совершает операции над векторами. Мы используем код c (...) для определения векторов (но даже если мы введем только одно значение, R сделает это самостоятельно).

Чтобы понять, как работают векторы, рассмотрим пример. Введите следующий код в сценарии, а не в консоли. Сначала создадим новый вектор, присвоив переменную x вектору c(1,2,3) с помощью оператора присваивания <-:

x <- c(1,2,3)

Теперь, когда у нас есть вектор, мы можем использовать его в расчетах. При выполнении простой операции, например добавления 3 к x и ввода результата в консоли, мы получаем довольно неожиданный вывод (особенно если вы привыкли к другому языку программирования):

> x + 3

[1] 4 5 6

Результат говорит нам, что произойдет, если мы добавим 3 к каждому значению в нашем векторе x. (Во многих других языках программирования нужно было бы использовать цикл for или какой-нибудь другой итератор для выполнения такой операции.)

Также можно складывать векторы друг с другом. Здесь мы создадим новый вектор, содержащий три элемента, каждый со значением 2. Назовем этот вектор y, а затем прибавим y к x:

> y <- c(2,2,2)

> x + y

[1] 3 4 5

Как видите, эта операция добавила каждый элемент в x к соответствующему элементу в y. А что, если умножить эти два вектора?

> x * y

[1] 2 4 6

Каждое значение в x умножается на соответствующее значение в y. Если бы списки не были одинакового размера или кратны одинаковому размеру, мы получили бы ошибку. Если вектор кратен одинаковому размеру, R будет просто многократно применять меньший вектор к большему. Но в этой книге эта операция не будет использоваться.

Мы можем довольно легко комбинировать векторы в R, определяя новый вектор на основе существующих. Здесь мы создадим вектор z путем объединения x и y:

> z <- c(x,y)

> z

[1] 1 2 3 2 2 2

Обратите внимание, что эта операция не вернула вектор векторов; вместо этого мы получили один вектор, который содержит значения обоих в том порядке, в котором x и y были заданы при определении z.

Эффективное использование векторов в R может поначалу показаться сложным. Как ни странно, программисты, которые имеют опыт работы с языками, не основанными на векторах, часто испытывают наибольшие трудности. Не беспокойтесь: в этой книге мы будем использовать векторы, чтобы упростить чтение кода.

Функции

Функции — это блоки кода, которые выполняют определенную операцию со значением, и мы будем использовать их в R для решения задач.

В R и RStudio все функции снабжены документацией. Если вы введете ?, за которым последует имя функции в консоли, то получите полную ­документацию по этой функции. Например, при вводе ?sum в консоли вы должны увидеть документацию в правом нижнем углу экрана (рис. A.3).

В документации дается определение функции sum() и некоторые варианты ее применения. Функция sum() принимает значения вектора и складывает их. В документации сказано, что она принимает ... в качестве аргумента, это означает, что она может принимать любое количество значений. Обычно эти значения представляют собой вектор чисел, но они также могут состоять из нескольких векторов.

В документации также указан необязательный аргумент: na.rm = FALSE. Необязательные аргументы — это аргументы, которые не нужно передавать в функцию, чтобы она работала; если вы не передадите необязательный аргумент, R будет использовать значение аргумента по умолчанию. В случае с na.rm, который автоматически удаляет все пропущенные значения, значением по умолчанию после знака равенства является FALSE. Это означает, что по умолчанию sum() не удалит пропущенные значения.

A_03.tif 

Рис. A.3. Просмотр документации для функции sum()

Основные функции

Вот некоторые из наиболее важных функций R.

Функции length() и nchar()

Функция length() возвращает длину вектора:

> length(c(1,2,3))

[1] 3

Поскольку в этом векторе три элемента, функция length() возвращает 3.

Поскольку все в R является вектором, можно использовать функцию length(), чтобы найти длину чего угодно — даже строки, например, doggies:

> length("doggies")

[1] 1

R говорит, что "doggies" — это вектор, содержащий одну строку.

Теперь, если бы у нас было две строки, "doggies" и "cats", мы бы получили:

> length(c("doggies", "cats"))

[1] 2

Чтобы найти количество символов в строке, используйте функцию nchar():

> nchar("doggies")

[1] 7

Обратите внимание, что если мы используем nchar() для вектора c("doggies","cats"), R вернет новый вектор, содержащий количество символов в каждой строке:

> nchar(c("doggies","cats"))

[1] 7 4

Функции sum(), cumsum() и diff()

Функция sum() принимает вектор чисел и складывает все эти числа:

> sum(c(1,1,1,1,1))

[1] 5

Из документации предыдущего раздела мы знаем, что sum() принимает ... в качестве аргумента, а это означает, что она может принять любое количество значений:

> sum(2,3,1)

[1] 6

> sum(c(2,3),1)

[1] 6

> sum(c(2,3,1))

[1] 6

Независимо от того, сколько векторов мы даем, sum() складывает их, как если бы они были одним вектором целых чисел. Если нужно суммировать несколько векторов, вызовите sum() для каждого из них по отдельности.

Помните также, что функция sum() принимает необязательный аргумент na.rm, который по умолчанию имеет значение FALSE. Аргумент na.rm определяет, удаляет ли sum() значения NA или нет.

Если мы оставим для na.rm значение FALSE, а затем попытаемся использовать sum() для вектора с отсутствующим значением, произойдет вот что:

> sum(c(1,NA,3))

[1] NA

Как мы видели, добавление любого значения к значению NA приводит к получению NA. Если нужно, чтобы R вместо предыдущего ответа возвращал число, можем дать команду sum() удалить значения NA, установив na.rm = TRUE:

> sum(c(1,NA,3),na.rm = TRUE)

[1] 4

Функция cumsum() принимает вектор и вычисляет его общую сумму — вектор той же длины, что и входной, который заменяет каждое число суммой чисел, предшествующих ему (включая это число). Вот пример кода:

> cumsum(c(1,1,1,1,1))

[1] 1 2 3 4 5

> cumsum(c(2,10,20))

[1] 2 12 32

Функция diff() принимает вектор и вычитает каждое число из числа, предшествующего ему в векторе:

> diff(c(1,2,3,4,5))

[1] 1 1 1 1

> diff(c(2,10,3))

[1] 8 -7

Обратите внимание, что результат функции diff() содержит на один элемент меньше, чем исходный вектор. Это потому, что из первого значения в векторе ничего не вычитается.

Оператор : и функция seq()

Чтобы не перечислять вручную каждый элемент вектора, можно генерировать векторы автоматически. Чтобы автоматически создать вектор целых чисел в определенном диапазоне, используется оператор :, чтобы отделить начало и конец диапазона. R может даже выяснить, нужно ли считать по направлению вверх или вниз (оборачивание этого оператора в c() не обязательно):

> c(1:5)

[1] 1 2 3 4 5

> c(5:1)

[1] 5 4 3 2 1

При использовании : R будет проводить подсчет от первого значения до последнего.

Иногда нужно посчитать что-то иным способом, кроме приращения на единицу. Функция seq() позволяет создавать векторы последовательности значений, которые увеличиваются на определенную величину. Аргументы seq() расположены по порядку:

1) начало последовательности;

2) конец последовательности;

3) величина, на которую нужно увеличить последовательность.

Вот несколько примеров использования seq():

> seq(1,1.1,0.05)

[1] 1.00 1.05 1.10

> seq(0,15,5)

[1] 0 5 10 15

> seq(1,2,0.3)

[1] 1.0 1.3 1.6 1.9

Если нужно отсчитать до определенного значения с помощью функции seq(), используйте отрицательное значение в качестве приращения, например:

> seq(10,5,-1)

[1] 10 9 8 7 6 5

Функция ifelse()

Функция ifelse() дает команду R выполнить одно из двух действий на основе некоторого условия. Эта функция может немного сбить с толку, если вы привыкли к обычной структуре управления if...else в других языках. В R она принимает следующие три аргумента (по порядку):

1) утверждение о векторе, которое может быть истинным или ложным по отношению к его значениям;

2) то, что происходит в случае, если утверждение истинно;

3) то, что происходит в случае, если утверждение ложно.

Функция ifelse() работает сразу с целыми векторами. Когда речь идет о векторах, содержащих одно значение, его использование интуитивно понятно:

> ifelse(2 < 3,"small","too big")

[1] "small"

Здесь утверждение состоит в том, что 2 меньше 3, и мы просим R вывести "small" («маленькое»), если это так, и "too big" («слишком большое»), если это не так.

Предположим, у нас есть вектор x, который содержит несколько значений:

> x <- c(1,2,3)

Функция ifelse() вернет значение для каждого элемента вектора:

> ifelse(x < 3,"small","too big")

[1] "small" "small" "too big"

Мы также можем использовать векторы в аргументах результатов для ifelse(). Предположим, что в дополнение к нашему вектору x был еще один вектор y:

y <- c(2,1,6)

Нужно создать новый список, который содержит наибольшее значение из x и y для каждого элемента в векторе. Можно использовать ifelse() в качестве очень простого решения:

> ifelse(x > y,x,y)

[1] 2 2 6

R сравнил значения в x с соответствующими значениями в y и вывел наибольшее из двух для каждого элемента.

Случайные выборки

Мы будем часто использовать R для случайной выборки значений. Это позволяет компьютеру выбрать случайное число или значение за нас. Мы используем этот пример для имитации таких действий, как подбрасывание монетки, игра в «камень, ножницы, бумага» или выбор числа от 1 до 100.

Функция runif()

Одним из способов случайной выборки значений является функция runif(), сокращение для «случайной последовательности», которая принимает требуемый аргумент n и возвращает это же число выборок в диапазоне от 0 до 1:

> runif(5)

[1] 0.8688236 0.1078877 0.6814762 0.9152730 0.8702736

Мы можем использовать эту функцию с ifelse() для генерации значения А в 20 % случаев. При этом мы будем использовать runif(5) для создания пяти случайных значений от 0 до 1. Затем, если значение меньше 0,2, мы вернем A; в противном случае вернем B:

> ifelse(runif(5) < 0.2,"A","B")

[1] "B" "B" "B" "B" "A"

Так как числа, которые мы генерируем, случайные, каждый раз при запуске функции ifelse() будут разные результаты. Вот некоторые возможные:

> ifelse(runif(5) < 0.2,"A","B")

[1] "B" "B" "B" "B" "B"

> ifelse(runif(5) < 0.2,"A","B")

[1] "A" "A" "B" "B" "B"

Функция runif() может принимать необязательные второй и третий аргументы, которые являются минимальным и максимальным значениями диапазона для случайной последовательности чисел. По умолчанию функция использует диапазон от 0 до 1 включительно, но вы можете установить любой диапазон:

> runif(5,0,2)

[1] 1.4875132 0.9368703 0.4759267 1.8924910 1.6925406

Функция rnorm()

Можно произвести выборку из нормального распределения, используя функцию rnorm(), которая подробно описана в главе 12:

> rnorm(3)

[1] 0.28352476 0.03482336 -0.20195303

По умолчанию rnorm() выбирает нормальное распределение со средним значением 0 и стандартным отклонением 1, как в этом примере. Это означает, что образцы будут иметь «колоколообразное» распределение около 0, при этом большинство образцов близко к 0, а очень мало — меньше –3 или больше 3.

Функция rnorm() имеет два необязательных аргумента, mean и sd, которые позволяют установить другое среднее значение и стандартное отклонение соответственно:

> rnorm(4,mean=2,sd=10)

[1] -12.801407 -9.648737 1.707625 -8.232063

В статистике выборка из нормального распределения часто более распространена, чем выборка из равномерного распределения, поэтому rnorm() очень удобна.

Функция sample()

Иногда нужно выбрать что-то еще, помимо хорошо изученного распределения. Предположим, у вас есть ящик с носками разных цветов:

socks <- c("red","grey","white","red","black")

Если нужно смоделировать случайный выбор любых двух носков, вы можете использовать функцию sample(), которая принимает в качестве аргументов вектор значений и количество элементов для выборки:

> sample(socks,2)

[1] "grey" "red"

Функция sample() ведет себя так, как если бы мы выбрали два случайных носка из ящика, не кладя их обратно. Если мы выберем пять носков, мы получим все носки, которые были в ящике:

> sample(socks,5)

[1] "grey" "red" "red" "black" "white"

Это означает, что если мы попытаемся взять шесть носков из ящика, где есть только пять, то получим ошибку:

> sample(socks,6)

Error in sample.int(length(x), size, replace, prob) :

cannot take a sample larger than the population when 'replace = FALSE'

Если нужно выполнить выборку и «положить носки обратно», мы можем установить необязательный аргумент replace в значение TRUE. Теперь каждый раз мы достаем носок и кладем его обратно в ящик. Это позволяет доставать больше носков, чем есть в ящике. Это также означает, что распределение носков в ящике никогда не меняется.

> sample(socks,6,replace=TRUE)

[1] "black" "red" "black" "red" "black" "black"

С помощью этих простых инструментов выборки можно запускать удивительно сложные симуляции в R, которые избавят вас от множества математических вычислений.

Использование set.seed() для предсказуемых случайных результатов

Случайные числа, сгенерированные R, не являются действительно случайными числами. Как и во всех языках программирования, случайные числа генерируются генератором псевдослучайных чисел, который принимает начальное значение и использует его для создания последовательности чисел, достаточно случайных для большинства целей. Начальное значение устанавливает начальное состояние генератора случайных чисел и определяет, какие числа будут выбраны в последовательности. В R мы можем вручную установить это начальное значение с помощью функции set.seed(). Установка начального значения чрезвычайно полезна в случаях, когда нужно снова использовать те же случайные результаты:

> set.seed(1337)

> ifelse(runif(5) < 0.2,"A","B")

[1] "B" "B" "A" "B" "B"

> set.seed(1337)

> ifelse(runif(5) < 0.2, "A","B")

[1] "B" "B" "A" "B" "B"

Когда мы дважды использовали один и тот же начальный фрагмент с функцией runif(), он сгенерировал один и тот же набор предположительно случайных значений. Основным преимуществом использования set.seed() является воспроизводимость результатов. Это может значительно упростить отслеживание ошибок в программах, связанных с выборкой, поскольку результаты не меняются при каждом запуске программы.

Определение собственных функций

Иногда полезно написать собственные функции для определенных операций, которые придется выполнять неоднократно. В R можно определять функции, используя ключевое слово functionключевое слово» в языке программирования — это просто специальное слово, зарезервированное для конкретного использования).

Вот определение функции, принимающей один аргумент, val, обозначающий значение, которое пользователь введет в функцию, а затем удваивает значение val и возводит его в куб.

double_then_cube <- function(val){

  (val*2)^3

}

После того как функция определена, ее можно использовать как встроенную функцию R. Вот наша функция double_then_cube(), примененная к числу 8:

> double_then_cube(8)

[1] 4096

Поскольку все, что мы делали для определения нашей функции, векторизовано (то есть все значения работают с векторами значений), функция будет работать и для векторов, и для отдельных значений:

> double_then_cube(c(1,2,3))

[1] 8 64 216

Мы также можем определить функции, которые принимают более одного аргумента. Определенная здесь функция sum_then_square() складывает два аргумента вместе, а затем возводит результат в квадрат:

sum_then_square <- function(x,y){

  (x+y)^2

}

Добавляя два аргумента (x, y) в функцию, в определении R мы указываем, что функция sum_then_square() ожидает два аргумента. Теперь мы можем использовать нашу новую функцию, например, следующим образом:

> sum_then_square(2,3)

[1] 25

> sum_then_square(c(1,2),c(5,3))

[1] 36 25

Также можно определить функции, которым требуется несколько строк. В R при вызове функции та всегда возвращает результат вычисления в последней строке определения. Это означает, что мы могли бы переписать sum_then_square() следующим образом:

sum_then_square <- function(x,y){

  sum_of_args <- x+y

  square_of_result <- sum_of_args^2

  square_of_result

}

Как правило, при написании функций вы создаете их в файле сценария R, чтобы можно было сохранить их и использовать позже.

Создание основных графиков в R

В R мы можем очень быстро создавать графики данных. Хотя R имеет необычную библиотеку графиков ggplot2, которая содержит множество полезных функций для генерации красивых графиков, мы пока ограничимся базовыми функциями построения графиков, которые сами по себе очень полезны. Чтобы показать, как работает построение графиков, создадим два вектора значений, xs и ys:

> xs <- c(1,2,3,4,5)

> ys <- c(2,3,2,4,6)

Затем мы можем использовать эти векторы в качестве аргументов функции plot(), которая построит для нас данные. Функция plot() принимает два аргумента: значения точек графика на оси Х и значения этих точек на оси Y в следующем порядке:

> plot(xs,ys)

Эта функция должна генерировать график, показанный на рис. A.4 в левом нижнем окне RStudio.

Этот график показывает взаимосвязь между нашими значениями xs и соответствующими им значениями ys. Если мы вернемся к функции, то сможем присвоить этому графику заголовок, используя необязательный аргумент main. Мы также можем изменить метки осей X и Y с помощью аргументов xlab и ylab, например:

plot(xs,ys,

     main="example plot",

     xlab="x values",

     ylab="y values"

     )

460019.png 

Рис. A.4. Простой график, созданный с помощью функции plot() в R

Новые метки должны отображаться так, как показано на рис. A.5.

Можно также изменить тип графика, используя аргумент type. Первый тип графика, который мы сгенерировали, называется точечным графиком, но если нужно создать линейный график, который рисует линию через каждое значение, следует установить type = "l":

plot(xs,ys,

     type="l",

     main="example plot",

     xlab="x values",

     ylab="y values"

     )

460029.png 

Рис. A.5. Изменение заголовка и меток графика с помощью функции plot()

Тогда это будет выглядеть так, как на рис. A.6.

460038.png 

Рис. A.6. Линейный график, сгенерированный с помощью функции plot() в R

Или мы можем сделать и то и другое! Функция R под названием lines() может добавлять линии к существующему графику. Он принимает большинство тех же аргументов, что и plot():

plot(xs,ys,

     main="example plot",

     xlab="x values",

     ylab="y values"

     )

lines(xs,ys)

На рис. A.7 показан график, который будет сгенерирован этой функцией.

460048.png 

Рис. A.7. Добавление линий к существующему графику с помощью функции lines() в R

Существует множество более удивительных способов использования основных графиков в R, и вы можете обратиться к ?plot для получения дополнительной информации о них. Но если вы хотите создавать действительно красивые графики в R, стоит изучить библиотеку ggplot2 (https://ggplot2.tidyverse.org/).

Упражнение: моделирование цен на бирже

Теперь давайте применим все свои навыки для создания имитации биржевого тикера! Люди часто моделируют цены на акции, используя общую сумму нормально распределенных случайных значений. Для начала мы будем моделировать движение запасов в течение определенного периода времени, генерируя последовательность значений от 1 до 20, увеличивая ее на 1 каждый раз с помощью функции seq(). Мы назовем вектор, представляющий период времени t.vals.

t.vals <- seq(1,20,by=1)

460058.png 

Рис. A.8. График, сгенерированный для моделируемого биржевого тикера

Теперь t.vals — это вектор, содержащий последовательность чисел от 1 до 20, увеличивающихся на 1. Далее создадим несколько смоделированных цен, взяв общую сумму нормально распределенного значения для каждого момента времени в t.vals. Для этого мы будем использовать rnorm() для выборки количества значений, равного длине t.vals. Затем используем cumsum() для вычисления общей суммы этого вектора значений, что будет представлять идею движения цены вверх или вниз на основе случайного сдвига; менее экстремальные сдвиги встречаются чаще, чем более экстремальные.

price.vals <- cumsum(rnorm(length(t.vals),mean=5,sd=10))

Наконец, можно построить график для всех этих значений, чтобы посмотреть, как они выглядят! Используем функции plot() и lines() и пометим оси в соответствии с тем, что они представляют.

plot(t.vals,price.vals,

     main="Simulated stock ticker",

     xlab="time",

     ylab="price")

lines(t.vals,price.vals)

Функции plot() и lines() должны сгенерировать график, показанный на рис. A.8.

Заключение

Приложение охватывает основы языка R в достаточном объеме, чтобы вы могли понять примеры из этой книги. Рекомендую следовать примерам из книги, а затем самостоятельно поэкспериментировать с примерами кода, чтобы закрепить знания. У языка R есть отличная онлайн-документация, что поможет вам в дальнейшем обучении (https://cran.r-project.org/manuals.html).

Назад: Приложения
Дальше: Б. Математический минимум