Где я могу научиться писать C код для ускорения медленных функций r? [закрыто
Вопрос
Какой лучший ресурс для обучения, как писать C код для использования с R? Я знаю о системные и иностранные интерфейсы Раздел «Расширения R», но я нахожу это довольно трудным. Какие хорошие ресурсы (как онлайн, так и офлайн) для написания C -кода для использования с R?
Чтобы уточнить, я не хочу учиться, как писать C-код, я хочу научиться лучше интегрировать R и C. Например, как я могу преобразовать из целочисленного вектора C до целочисленного вектора R (или наоборот) Или из скакара в вектор r?
Решение
Ну, есть старый добрый Используйте источник, Luke! --- r сама имеет много (очень эффективное) C Code можно изучить, и у крана есть сотни пакетов, некоторые из авторов вы доверяете. Это дает реальные, проверенные примеры для изучения и адаптации.
Но как подозревается Джош, я склоняюсь к C ++ и, следовательно, RCPP.. Отказ Он также имеет много примеров.
Редактировать: Было две книги, которые я нашел полезным:
- Первый - завтраки и Рипли "S Программирование«Несмотря на то, что в зубе продолжается (и слухи о 2-м издании в течение многих лет). В то время было просто больше ничего.
- Второй в камерах '"Программное обеспечение для анализа данных«Что гораздо более недавнее и имеет гораздо приятнее R-ориентированное ощущение - и две главы о расширении R. Как упомянуты как C и C ++. Кроме того, Джон отбрасывает меня за то, что я сделал с переварить Так что только стоит цена приема.
Что сказал, Джон растет любит RCPP. (и вклад), поскольку он находит матч между объектами R и объектами C ++ (через RCPP.) быть очень естественным - и резонансы там помогают там.
Редактировать 2: С перефокусом Хадли, я очень сильно Призываю вас рассмотреть C ++. Есть так много ерунды ботина, которую вы должны сделать с C - очень утомительно и Очень ударенно. Отказ Посмотреть на RCPP-введение виньетки. Отказ Еще один простой пример этот блог пост где я показываю, что вместо того, чтобы беспокоиться около 10% различий (в одном из примеров Radford Neal) мы можем получить восемьдесят раз Увеличивается с C ++ (на что, конечно, надуманный пример).
Редактировать 3: В том, что вы можете столкнуться с ошибками C ++, которые являются мягкими, трудно GROK. Но чтобы просто использовать RCPP Вместо того, чтобы продлить это, вам вряд ли нужно это понадобиться. И пока это Стоимость неоспорим, он далеко затменяется польза Из проще всего кода, менее котельной, без защиты / не защищены, никаких управлений памяти и т. Д. Дуг Бейтс только вчера заявил, что он находит C ++ и RCPP, чтобы быть гораздо больше похоже на запись R, чем писать C ++. YMMV и все это.
Другие советы
Хэдли,
Вы определенно можете написать код C ++, который похож на C Code.
Я понимаю, что вы говорите о C ++ более сложным, чем C. Это если вы хотите освоить все: объекты, шаблоны, STL, шаблон Meta Programming и т. Д. Большинство людей не нуждаются в этих вещах и могут просто полагаться на других к этому. Реализация RCPP очень сложна, но только потому, что вы не знаете, как работает ваш холодильник, это не значит, что вы не можете открыть дверь и захватить свежее молоко ...
Из вашего многочисленного вклада в R, что мне поражает, что вы найдете r несколько утомительно (манипуляция данных, графика, струнная манипуляция и т. Д.). Хорошо подготовить гораздо больше сюрпризов с внутренним C API R. Это очень утомительно.
Время от времени я читаю руководства R-EXTS или R-INTS. Это помогает. Но большую часть времени, когда я действительно хочу узнать о чем-то, я иду в источник R, а также в источнике пакетов, написанных EG Simon (обычно есть много, чтобы узнать там).
RCPP предназначен для того, чтобы эти утомительные аспекты API уходят.
Вы можете судить о себе, что вы найдете более сложным, запутанным и т. Д., Основываясь на нескольких примерах. Эта функция создает вектор символа с помощью API C:
SEXP foobar(){
SEXP ab;
PROTECT(ab = allocVector(STRSXP, 2));
SET_STRING_ELT( ab, 0, mkChar("foo") );
SET_STRING_ELT( ab, 1, mkChar("bar") );
UNPROTECT(1);
}
Используя RCPP, вы можете написать ту же функцию, что и:
SEXP foobar(){
return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}
или:
SEXP foobar(){
Rcpp::CharacterVector res(2) ;
res[0] = "foo" ;
res[1] = "bar" ;
return res ;
}
Как сказал Дирк, есть другие примеры на нескольких виньетках. Мы также обычно указываем на наших модульных тестах, потому что каждый из них тестирует очень специфическую часть кода и несколько явно объяснил.
Я явно предвзятый здесь, но я бы порекомендовал узнать о RCPP вместо того, чтобы изучить API ap r, а затем прийти к списку рассылки, если что-то неясно или не кажется выполненным с RCPP.
В любом случае, конец подачи продаж.
Я думаю, все зависит от того, какой код вы хотите написать в конце концов.
Роман
@hadley: К сожалению, у меня имейте в виду конкретных ресурсов, чтобы помочь вам начать работу на C ++. Я поднял его из книг Скотта Мейерса (эффективный C ++, более эффективный C ++, и т. Д. ...) Но это не совсем то, что можно вызвать вводным.
Мы почти исключительно используем интерфейс .call для вызова кода C ++. Правило достаточно легко:
- Функция C ++ должна вернуть объект R. Все объекты R - это сексP.
- Функция C ++ занимает от 0 до 65 r объектов в качестве входа (снова SEXP)
- это должно (не совсем, но мы можем сохранить это на потом) быть объявленным с помощью ссылки C, либо с Extern "C" или RCPPEXPORT. Псевдоним, что RCPP определяет.
Таким образом, функция .call объявляется, как это в некотором файле заголовка:
#include <Rcpp.h>
RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;
и реализован, как это в файле .cpp:
SEXP foo( SEXP x1, SEXP x2 ){
...
}
Значит не намного больше, чтобы знать о R API, чтобы использовать RCPP.
Большинство людей хотят только иметь дело с числовыми векторами в RCPP. Вы делаете это с классом NumericVector. Есть несколько способов создать числовой вектор:
Из существующего объекта, который вы передаете от R:
SEXP foo( SEXP x_) {
Rcpp::NumericVector x( x_ ) ;
...
}
С заданными значениями, используя статическую функцию :: Create статичность:
Rcpp::NumericVector x = Rcpp::NumericVector::create( 1.0, 2.0, 3.0 ) ;
Rcpp::NumericVector x = Rcpp::NumericVector::create(
_["a"] = 1.0,
_["b"] = 2.0,
_["c"] = 3
) ;
Данного размера:
Rcpp::NumericVector x( 10 ) ; // filled with 0.0
Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0
Затем, как только у вас есть вектор, самое полезное, чтобы извлечь один элемент из него. Это сделано с оператором [], с 0 индексированием на основе 0, поэтому, например, суммирование значений числового вектора идет что-то подобное:
SEXP sum( SEXP x_ ){
Rcpp::NumericVector x(x_) ;
double res = 0.0 ;
for( int i=0; i<x.size(), i++){
res += x[i] ;
}
return Rcpp::wrap( res ) ;
}
Но с сахаром RCPP мы можем сделать это гораздо более красиво сейчас:
using namespace Rcpp ;
SEXP sum( SEXP x_ ){
NumericVector x(x_) ;
double res = sum( x ) ;
return wrap( res ) ;
}
Как я уже говорил, все зависит от того, какой код вы хотите написать. Посмотрите, что люди делают в пакетах, которые полагаются на RCPP, проверьте виньетки, агрегаты, вернитесь к нам в списке рассылки. Мы всегда рады помочь.
@jbremnant: Это верно. Классы RCPP реализуют что-то близко к рисунку Raii. Когда создается объект RCPP, конструктор принимает соответствующие меры для обеспечения того, чтобы базовый объект R (SEXP) защищен от сборщика мусора. Деструктор снимает защиту. Это объясняется в RCPP-вторжение виньетка. Основная реализация опирается на функции API r R_preserveObject. и R_releaseObject.
Существует действительно штраф производительности из-за инкапсуляции C ++. Мы стараемся сохранить это как минимум с помощью встроенного, и т. Д. Функция небольшой, и когда вы учитываете усиление с точки зрения времени, необходимого для записи и поддержания кода, это не так важно.
Вызов R Функции из класса RCPP Made Moneeler, чем напрямую вызова EVI с API C. Это связано с тем, что мы принимаем меры предосторожности и завернули функцию вызова функции в блок Trycatch, чтобы мы получили ошибки R и продвигаем их к исключениям C ++, чтобы они могли рассматриваться с использованием стандартной попытки в C ++.
Большинство людей хотят использовать векторы (специально numericvector), а штраф очень маленький с этим классом. Справочник примеров / CONVULDBENCHMARKS содержит несколько вариантов известной функции свертки из R-EXTS, а Vignette имеет ориентирные результаты. Оказывается, что RCPP делает его быстрее, чем тестовый код, который использует R API.