Установка R в Ubuntu. Как сравнивать векторы, элементы векторов

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

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

  • Подключайте более мощные параллельные библиотеки, например, Intel BLAS (доступна под Linux, OS X и Windows как часть дистрибутива Microsoft R Open). Это позволит заменить уже используемые библиотеки их параллельными версиями, благодаря чему получите ускорение (на соответствующих задачах, например, связанных с линейной алгеброй в lm()/glm()).
  • Вынесите обработку задач моделирования из R во внешнюю библиотеку для параллелизации . Это стратегия, которую используют следующие системы: методы rx от RevoScaleR (теперь Microsoft Open R) , методы h2o от h2o.ai , RHadoop .
  • Используйте утилиту parallel в R, чтобы запускать функции на других экземплярах R . Эта стратегия из «Небольшого введения в параллельное программирование на R» и ряда библиотек на основе parallel . Фактически это реализация удаленного вызова процедуры через сокет или сеть.

Рассмотрим подробнее третий подход.

Фактически, третий подход представляет собой очень мелко подробленный удаленный вызов процедуры. Он зависит от передачи копий кода и данных на удаленные процессы и последующий возврат результатов. Это плохо подходит для очень маленьких задач, но отлично - для приемлемого числа средних или больших. Эта стратегия используется в библиотеке R parallel и в библиотеке Python multiprocessing (хотя с multiprocessing для Python может понадобиться ряд дополнительных библиотек , чтобы перейти от одной машины к кластерным вычислениям).

Этот метод может показаться менее эффективным и менее сложным, чем методы распределенной памяти, но полагаясь на передачу объекта, можно очень легко распространить технику от одной машины на несколько («кластерные вычисления»). Именно это мы сделаем с помощью кода на R в этой статье (переход от одной машины к кластеру приведет к многочисленным проблемам систем/сети/безопасности, и с ними придется справляться).

Вам понадобится весь код на R из предыдущей статьи. Также предполагается, что вы можете сконфигурировать ssh , или у вас есть человек, который может помочь с настройкой. Вместо запуска параллельного кластера командой “ parallelCluster <- parallel::makeCluster(parallel::detectCores()) ” сделайте следующее.

Соберите список адресов машин, к которым вы можете применить ssh . Это сложная часть, зависит от операционной системы и может потребовать помощи, если вы раньше этого не делали. В этом примере я использую IPv4 адреса, а для Amazon EC2 - имена узлов.

В моем случае список такой:

  • Моя машина (основная): “192.168.1.235”, пользователь “johnmount”
  • Другая машина Win-Vector LLC: “192.168.1.70”, пользователь “johnmount”

Обратите внимание, мы не собираем пароли, предполагая, что установлены правильные «authorized_keys» и пары ключей в конфигурациях ".ssh" всех этих машин. Будем называть машину, с которой будет осуществляться расчет в целом, «первичной».

Обязательно стоит попробовать все эти адреса с «ssh» в терминале перед тем, как использовать их в R. Также адрес машины, выбранной «первичной», должен быть достижим с рабочих машин (т.е. нельзя использовать «localhost» или выбирать недостижимую машину «первичной»). Попробуйте вручную ssh между первичной и остальными машинами, и в обратную сторону, после чего настройки можно будет использовать в R.

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

Primary <- "192.168.1.235" machineAddresses <- list(list(host=primary,user="johnmount", ncore=4), list(host="192.168.1.70",user="johnmount", ncore=4)) spec <- lapply(machineAddresses, function(machine) { rep(list(list(host=machine$host, user=machine$user)), machine$ncore) }) spec <- unlist(spec,recursive=FALSE) parallelCluster <- parallel::makeCluster(type="PSOCK", master=primary, spec=spec) print(parallelCluster) ## socket cluster with 8 nodes on hosts ## ‘192.168.1.235’, ‘192.168.1.70’

Вот и все. Теперь можно запускать ваши функции на нескольких ядрах нескольких машин. Для правильных задач ускорение будет существенным . Всегда имеет смысл действовать пошагово: сначала напишите простой «hello world» на вашем кластере, потом убедитесь, что меньшая версия ваших расчетов работает локально, и только после этого переносите работу в кластер.

Есть и другой способ работать с кластерами в R. Для начала нам понадобится версия R с предуслатновленными пакетами Rmpi и snow. Для этой цели я предлагаю билд R HSPCC, поддерживаемый Каспером Дэниэлом Хансеном. Вот инструкции по установке.

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

Использование нескольких ядер внутри узла

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

Запустите процесс на узле кластера с несколькими процессорами, набрав следующую команду:

Qrsh -l mcmc -pe local 10-12

Обратите внимание, здесь мы запрашиваем 10-12 процессоров на одном узле в очереди mcmc. Количество доступных ядер можно посмотреть в переменной окружения NSLOTS, доступной в R с помощью такой команды:

As.integer(Sys.getenv("NSLOTS"))

Следующий шаг - запустить R и загрузить библиотеку multicore. Наконец, можно продолжить использованием команды mclapply вместо lapply в R (передавая количество используемых ядер как аргумент mc.cores).

Использование snow между несколькими узлами

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

Для запуска кластера MPI с 12 узлами (ядрами), нужно набрать такое:

Qrsh -V -l cegs -pe orte 12 /opt/openmpi/bin/mpirun -np 12 ~hcorrada/bioconductor/Rmpi/bstRMPISNOW

Эта команда должна запустить 12 экземпляров R, один из которых будет первичным. Обратите внимание, стартовый процесс был в очереди cegs. Затем вы можете пользоваться узлами, установленными с помощью mpirun, набрав в R такое:

Cl <- getMPIcluster()

Затем можно просмотреть и воспользоваться нужными вам командами snow. Например,

ClusterCall(cl, function() Sys.info())

выдаст список узлов вашего кластера (если точнее, 11 запущенных рабочих узлов). находится список доступных команд.

Когда вычисления на кластере завершены, нужно закрыть узлы следующей командой:

StopCluster(cl)

Предупреждение: удостоверьтесь, что вы не отменили процессы R нажатием комбинации клавиш Ctrl+C. Это может вызвать проблемы со snow.

Пример: сравнение последовательной и параллельной обработки

> f.long<-function(n) { + xx<-rnorm(n) + log(abs(xx))+xx^2 + } #Использование multicore ############ > system.time(mclapply(rep(5E6,11),f.long,mc.cores=11)) user system elapsed 26.271 3.514 5.516 #Использование snow через MPI ############ > system.time(sapply(rep(5E6,11),f.long)) user system elapsed 17.975 1.325 19.303 > system.time(parSapply(cl,rep(5E6,11),f.long)) user system elapsed 4.224 4.113 8.338

Обратите внимание, параллельная обработка со snow дает улучшение более чем в 50% времени вычисления. Хотя можно предполагать, что улучшение должно составлять 10/11=91%, важно помнить, что процессоры не обязательно находятся на одном и том же узле, и взаимодействие между узлами может быть довольно медленным. Это взаимодействие может быть настолько медленным, что процедура на multicore без него может дать 40%-ое улучшение времени вычисления.

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

Чтобы создать переменную (например, х) и присвоить ей значение (например, 1234) нужно просто ввести команду х=1234 . Теперь в любых выражениях имя переменной (в нашем случае х) будет автоматически заменено значением (у нас это 1234).

Чтобы узнать значение переменной, достаточно ввести название переменной, и R выдаст ее значение. Выглядеть это будет так:
> x=1234
> х
1234

Присваивая переменной новое значение, можно использовать старое значение, то есть создавать конструкции типа
> a=5
> a
5
> a=a+3
> a
8

Важно знать, что имена переменных могут состоять из латинских букв обоих регистров, из цифр и знаков подчеркивания (например, допустимы такие имена: a, x, x1, a_x, O_o, the_Variable_with_Long_Name, a459x4h36J4lbgT62). При этом первым символом должна обязательно являться буква! Наконец, регистр имеет значение, то есть RainForest и RainFOrest - это разные переменные.

Векторы, или как работать с рядами данных?

Что такое векторы в R?

Допустим, у нас есть группа из 5 человек, и нам надо сохранить их возраста. Можно создать пять переменных, например
> age_1=25
> age_2=20
> age_3=9
> age_4=44
> age_5=37
Однако удобнее создать одну переменную, в которую поместить все 5 значений. Такой ряд данных, объединенных одним именем, хранящийся в определенном порядке - это массив данных, или вектор.

Assign("age",c(25,20,9,44,37))
или сокращенно: age

Теперь, каждый отдельный элемент можно вызвать по его порядковому номеру в ряду, например, четвертый элемент можно получить так:
> age
44
С такими отдельными элементами можно производить все те же операции, что и с обычными числами

Функция append, или как добавить элементы в существующий вектор?

Допустим, в нашей группе появился еще один человек, возраст которого 31 год. Мы можем создать заново вектор age, но теперь из шести элементов вместо пяти. Однако есть другой способ - использовать функцию append:
> append(age,31)
25 20 9 44 37 31
Замечу, что мы могли бы вставить несколько значений, вспомнив про функцию c():
> append(age,c(31,33,35))
25 20 9 44 37 31 33 35

Также функция позволяет вставить элементы в любом месте вектора с помощью параметра after. По умолчанию установлено значение after=length(x), то есть элементы добавляются в конец. Но допустим, мы захотим вставить нашего шестого человека после второго:
> append(age, 31, after=2)
25 20 31 9 44 37

Операции с векторами, или что можно делать с векторами?

Можно оперировать всеми элементами вектора одновременно. Так прибавление числа к вектору равносильно прибавление этого числа к каждому элементу вектора. Или, например, чтобы вывести, сколько десяктов лет прожил каждый человек из нашего примера, можно сделать так:
> age/10
2.5 2.0 0.9 4.4 3.7

Аналогично со сложением, вычитанием и другими операциями, описанными в пункте про

Как сравнивать векторы, элементы векторов?

Допустим, нужно выяснить, какие элементы вектора (пусть будет тот же age) больше определенного числа (например, кто из нашей маленькой выборки совершеннолетний). R для каждого элемента скажет, выполняется ли условие, то есть TRUE (верно) или FALSE (не верно) Выглядеть будет примерно так:
>age
25 20 31 9 44 37
> age >= 18
TRUE TRUE FALSE TRUE TRUE

Но может понадобиться получить один ответ, например, верно ли, что все элементы соответствуют условию? или есть ли вообще элементы, соответствующие условию? Для этого используем две функции, соответственно, all() и any()

all(x1,x2,...,xn) - ответит на вопрос, верно ли, что все условия (x1, x2, ... и xn) верны? то есть это логическая конъюнкция. Например:
> all (age >= 7, age TRUE
# действительно, все испытуемые не младше семи и младше шестидесяти
> all (age >=18, 1 > 0)
FALSE
# хотя единица, конечно, больше нуля, но среди наших испытуемых есть один девятилетний, поэтому не верно

any(x1,x2,...,xn) - ответит на вопрос, есть ли среди условий (x1, x2, ..., xn) хоть одно верное? то есть это логическая дизъюнкция. Пример:
> any (age >=18, 1 > 0)
TRUE

Наконец, можно сравнивать между собой два вектора. Но для этого нужно либо чтобы длина большего была кратна длине меньшего либо чтобы длины были равны. Примеры:
> a > a > b
FALSE FALSE FALSE TRUE TRUE

Как задать последовательность чисел?

  • оператор:
  • seq(from,to,by,length,along) - создает последовательность, начиная с from, заканчивая to с шагом by. Можно задать длину ряда параметром length или приравнять по длине к другому вектору along . Аргументы: from, to, by, length, along (такой же длины как...)
  • rep(a, times, each) - повторять вектор a times раз или each раз каждый элемент a. Аргументы: вектор, times, each

Сортировка

  • sort(v,increasing) - сортирует вектор v; increasing - булев, true - по возрастанию, false - по убыванию, можно вместо этого написать increasing=decreasing;
  • order()

При работе с R скриптом может потребоваться обновлять его автоматически. Пакет “taskscheduleR” помогает настроить расписание для запуска R скрипта в Windows Task Schedule ежедневно, еженедельно, каждые N минут, после запуска Windows и так далее.

  1. Устанавливаем пакет “taskscheduleR” library(devtools) install.packages("devtools") install_github("jwijffels/taskscheduleR") library(taskscheduleR)

    Используем пакет «devtools», который позволяет скачивать и устанавливать пакеты напрямую с GitHub.

  2. Далее для настройки запуска скрипта можно воспользоваться либо интерактивной настройкой через форму, либо написав пару строк кода.

Настройка расписания R скрипта в Task Scheduler через Addins:

Настройка расписания R скрипта через функции пакета taskscheduleR:

Функции пакета:

  • Получить список всех задач в Windows Task Sheduler
  • Удалить задачу из Windows Task Sheduler
  • Добавить задачу запуска R скрипта
    • Доступны следующие расписания: ‘ONCE’, ‘MONTHLY’, ‘WEEKLY’, ‘DAILY’, ‘HOURLY’, ‘MINUTE’, ‘ONLOGON’, ‘ONIDLE’
## Указываем название файла R скрипта для последующей работы с ним myscript <- system.file("extdata", "helloworld.R", package = "taskscheduleR") ## Запуск скрипта разово через 35 секунд taskscheduler_create(taskname = "myscript", rscript = myscript, schedule = "ONCE", starttime = format(Sys.time() + 35, "%H:%M")) ## Запуск скрипта ежедневно в 10:15, начиная с завтрашнего дня ## Важно: необходимо поменять формат даты, если он не совпадает с тем, что стоит на компьютере (пример: %m/%d/%Y) taskscheduler_create(taskname = "myscriptdaily", rscript = myscript, schedule = "DAILY", starttime = "10:15", startdate = format(Sys.Date()+1, "%d/%m/%Y")) ## Запуск скрипта каждую неделю в 10:15 по понедельникам taskscheduler_create(taskname = "myscript_mon", rscript = myscript, schedule = "WEEKLY", starttime = "10:15", days = "MON") ## Запуск каждые 5 минут, начиная с 10:15 taskscheduler_create(taskname = "myscript_5min", rscript = myscript, schedule = "MINUTE", starttime = "10:15", modifier = 5) ## Получить data.frame со всеми задачами tasks <- taskscheduler_ls() str(tasks) ## Удалить задачи taskscheduler_delete(taskname = "myscript") taskscheduler_delete(taskname = "myscriptdaily") taskscheduler_delete(taskname = "myscript_,mon") taskscheduler_delete(taskname = "myscript_5min") taskscheduler_delete(taskname = "myscript_withargs_a") taskscheduler_delete(taskname = "myscript_withargs_b")

На что обращаем внимание:

  • Формат даты . Он должен совпадать с форматом даты на компьютере. В противном случае получим либо ошибку настройки расписания запуска скрипта, либо совсем другую дату.
  • Активность компьютера . Компьютер должен быть включен в момент запуска скрипта
  • Наличие других расписаний скрипта . При настройке нового расписания с тем же названием, предыдущее расписание удаляется.

Вы можете использовать system() и Rscript для запуска сценария как асинхронного фонового процесса:

system ("Rscript -e "source(\"your-script.R\")"" , wait = FALSE ) ... save.image ("script-output.RData" ) cat ("Script completed\n\n" )

Надеюсь это поможет!

Я хочу выполнить R-сценарий в фоновом режиме с консоли R.

С консоли я обычно запускаю R-скрипт как источник ("~ / .active-rstudio-document). Мне нужно подождать, пока скрипт не будет завершен, чтобы продолжить работу. Вместо этого я хочу, чтобы R работал в фоновом режиме, пока я могу продолжить работу в консоли. Также я должен быть как-то уведомлен, когда R завершает команду источника. Возможно ли это в R?

Это может быть весьма полезно, поскольку мы часто видим, что работа занимает много времени.

PS - Я хочу, чтобы исходный скрипт работал в том же пространстве памяти, а не в новом. Поэтому решения, такие как fork, system и т. Д., Не будут работать для меня. Я вижу, могу ли я запустить R-скрипт как отдельный поток, а не отдельный процесс.