Где я могу научиться писать C код для ускорения медленных функций r? [закрыто

StackOverflow https://stackoverflow.com/questions/4106174

  •  29-09-2019
  •  | 
  •  

Вопрос

Какой лучший ресурс для обучения, как писать 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top