Ну вот и старый добрый. Используй источник, Люк! --- Сам R имеет много (очень эффективного) кода C, который можно изучить, а в CRAN есть сотни пакетов, некоторые от авторов, которым вы доверяете. Это дает реальные проверенные примеры для изучения и адаптации.
Но, как и подозревал Джош, я больше склоняюсь к C ++ и, следовательно, к Rcpp . Там тоже много примеров.
Изменить: я нашел две полезные книги:
- Первый - это « S-программирование » Венейблса и Рипли, хотя он и набирает обороты (слухи о втором издании ходили годами). В то время другого просто не было.
- Вторая в « Программном обеспечении для анализа данных » Чемберса, которая появилась гораздо позже и имеет гораздо более приятное ощущение R-ориентированности, и две главы о расширении R. Упоминаются как C, так и C ++. Кроме того, Джон шлепает меня за то, что я сделал с дайджестом, так что одно это стоит цены входа.
Тем не менее, Джон все больше любит Rcpp (и вносит свой вклад), так как считает соответствие между объектами R и объектами C ++ (через Rcpp ) очень естественным - и в этом помогают ReferenceClasses.
Изменить 2: с перефокусированным вопросом Хэдли я очень настоятельно призываю вас рассмотреть C ++. Существует так много шаблонной ерунды, которую вы должны делать с C --- очень утомительно, и ее очень легко избежать . Взгляните на виньетку с введением Rcpp . Другой простой пример - это сообщение в блоге, где я показываю, что вместо того, чтобы беспокоиться о 10% различиях (в одном из примеров Рэдфорда Нила), мы можем получить восьмидесятикратное увеличение с помощью C ++ (это, конечно, надуманный пример).
Изменить 3: есть сложность в том, что вы можете столкнуться с ошибками C ++, которые, мягко говоря, трудно понять. Но чтобы просто использовать Rcpp, а не расширять его, он вам вряд ли когда-нибудь понадобится. И хотя эта стоимость неоспорима, она намного затмевается преимуществами более простого кода, меньшего количества шаблонов, отсутствия PROTECT / UNPROTECT, никакого управления памятью и т. Д. Дуг Бейтс только вчера заявил, что он считает, что C ++ и Rcpp намного больше похожи на написание R чем писать на C ++. YMMV и все такое.
ggplot
?Хэдли,
Вы определенно можете написать код C ++, похожий на код C.
Я понимаю, что вы говорите о том, что C ++ более сложен, чем C. Это если вы хотите освоить все: объекты, шаблоны, STL, метапрограммирование шаблонов и т.д ... большинству людей эти вещи не нужны, и они могут просто полагаться на других к нему. Реализация Rcpp очень сложна, но то, что вы не знаете, как работает ваш холодильник, не означает, что вы не можете открыть дверь и взять свежее молоко ...
Из ваших многочисленных вкладов в R меня поразило то, что вы находите R несколько утомительным (манипулирование данными, графика, манипуляции со строками и т. Д.). Будьте готовы к еще большему количеству сюрпризов с внутренним C API R. Это очень утомительно.
Время от времени я читал руководства по R-exts или R-ints. Это помогает. Но в большинстве случаев, когда я действительно хочу что-то узнать, я обращаюсь к исходному тексту R, а также к источнику пакетов, написанному, например, Саймоном (обычно там есть чему поучиться).
Rcpp разработан, чтобы избавиться от этих утомительных аспектов API.
Вы можете сами судить, что вам кажется более сложным, запутанным и т. Д., На основе нескольких примеров. Эта функция создает вектор символов с помощью C API:
Используя Rcpp, вы можете написать такую же функцию, как:
или:
Как сказал Дирк, в нескольких виньетках есть и другие примеры. Мы также обычно указываем людям на наши модульные тесты, потому что каждый из них тестирует очень конкретную часть кода и в некоторой степени не требует пояснений.
Я здесь явно предвзято, но я бы рекомендовал познакомиться с Rcpp вместо изучения C API R, а затем перейти к списку рассылки, если что-то неясно или не представляется возможным с Rcpp.
В любом случае, конец коммерческой презентации.
Я думаю, все зависит от того, какой код вы хотите написать в конечном итоге.
Ромен
источник
@hadley: к сожалению, у меня нет конкретных ресурсов, которые помогут вам начать работу с C ++. Я взял его из книг Скотта Мейерса («Эффективный С ++», «Более эффективный С ++» и т. Д.), Но это не совсем то, что можно было бы назвать вводным.
Мы почти исключительно используем интерфейс .Call для вызова кода C ++. Правило достаточно простое:
Итак, в каком-то заголовочном файле функция .Call объявляется следующим образом:
и реализован так в файле .cpp:
О том, что R API будет использовать Rcpp, мало что нужно.
Большинство людей хотят иметь дело только с числовыми векторами в Rcpp. Вы делаете это с помощью класса NumericVector. Есть несколько способов создать числовой вектор:
Из существующего объекта, который вы передаете от R:
С заданными значениями с использованием статической функции :: create:
Заданного размера:
Затем, когда у вас есть вектор, самое полезное - извлечь из него один элемент. Это делается с помощью оператора [] с индексированием на основе 0, поэтому, например, суммирование значений числового вектора происходит примерно так:
Но с сахаром Rcpp мы можем сделать это намного лучше:
Как я уже сказал, все зависит от того, какой код вы хотите написать. Посмотрите, что люди делают в пакетах, которые полагаются на Rcpp, проверьте виньетки, модульные тесты, вернитесь к нам в список рассылки. Мы всегда рады помочь.
источник
@jbremnant: Верно. Классы Rcpp реализуют что-то близкое к шаблону RAII. Когда создается объект Rcpp, конструктор принимает соответствующие меры для обеспечения защиты базового объекта R (SEXP) от сборщика мусора. Деструктор снимает защиту. Это объясняется в виньетке Rcpp-intrduction . Базовая реализация полагается на функции R API R_PreserveObject и R_ReleaseObject.
Действительно, из-за инкапсуляции C ++ наблюдается снижение производительности. Мы стараемся свести это к минимуму с помощью встраивания и т. Д. Штраф небольшой, и когда вы принимаете во внимание выигрыш с точки зрения времени, необходимого для написания и поддержки кода, это не так важно.
Вызов функций R из класса Function Rcpp выполняется медленнее, чем прямой вызов eval с помощью C api. Это связано с тем, что мы принимаем меры предосторожности и заключаем вызов функции в блок tryCatch, чтобы мы фиксировали ошибки R и продвигали их в исключения C ++, чтобы их можно было обрабатывать с помощью стандартного метода try / catch в C ++.
Большинство людей хотят использовать векторы (особенно NumericVector), и штраф за этот класс очень невелик. Каталог examples / ConvolveBenchmarks содержит несколько вариантов пресловутой функции свертки из R-exts, а виньетка содержит результаты тестов. Оказывается, Rcpp делает это быстрее, чем тестовый код, использующий R API.
источник