2016-02-25 2 views
0

Я работаю в R, используя библиотеки C. Мне нужно передать функции C массив с числами от 1 до 10, но это также может быть «NA». Затем в C, в зависимости от значения, мне нужно установить выход. Вот упрощенный код, проходящий в R-массиве до функции C с «NA»

heredyn.load("ranking.so") 

fun <- function(ranking) { 
    nrak <- length(ranking) 
    out <- .C("ranking", as.integer(nrak), as.character(ranking), rr = as.integer(vector("integer",nrak))) 
    out$rr 
} 

ranking <- sample(c(NA,seq(1,10)),10,replace=TRUE) 
rr <- fun(ranking) 

Функция C может просто быть таким, как

#include <R.h> 

void ranking(int *nrak, char *ranking, int *rr) { 
    int i ; 

    for (i=0;i<*nrak;i++) { 
    if (ranking[i] == 'NA') 
     rr[i] = 1 ; 
    else 
     rr[i] = (int) strtol(&ranking[i],(char **)NULL,10) ; 
    } 
} 

Благодаря значению «NA» Я поставил рейтинг как характер, но может быть, есть другой способ сделать это, используя число и не заменяя «NA» на 0 перед вызовом функции?

(код, как это дает мне всегда массив нулей ...)

+1

Не указывайте константу _null указателя_, заданную макросом 'NULL'. Общее правило - не использовать ненужные броски. – Olaf

+0

ok. спасибо! но я не думаю, что это преодолевает проблему. – Stefano

+1

Комментарий не для ответа. – Olaf

ответ

6

испытаний для того, является ли значение Ч использование R_NaInt, как

#include <R.h> 

void ranking_c(int *nrak, int *ranking, int *rr) { 
    for (int i=0; i < *nrak; i++) 
     rr[i] = R_NaInt == ranking[i] ? -1 : ranking[i]; 
} 

Invoke из R, явно позволяя ВПЛ

> x = c(1:2, NA_integer_) 
> .C("ranking_c", length(x), as.integer(x), integer(length(x)), NAOK=TRUE)[[3]] 
[1] 1 2 -1 

В качестве альтернативы, использовать интерфейс R в .Call(). Каждый объект R представляется как S-выражение. Существуют функции C-уровня для управления S-выражениями, например длиной Rf_length(), доступом к данным INTEGER() и распределением Rf_allocVector() различных типов S-выражений, таких как INTSXP для целых векторов.

Управление памятью R использует сборщик мусора, который может работать на любом вызове, который выделяет память. Поэтому наилучшей практикой является PROTECT() любое распределение R во время действия.

Ваша функция принимает 0 или более S-выражений в качестве входных данных и возвращает одно S-выражение; она может быть реализована как

#include <Rinternals.h> 
#include <R_ext/Arith.h> 

SEXP ranking_call(SEXP ranking) 
{ 
    /* allocate space for result, PROTECTing from garbage collection */ 
    SEXP result = PROTECT(Rf_allocVector(INTSXP, Rf_length(ranking))); 

    /* assign result */ 
    for (int i = 0; i < Rf_length(ranking); ++i) 
     INTEGER(result)[i] = 
      R_NaInt == INTEGER(ranking)[i] ? -1 : INTEGER(ranking)[i]; 

    UNPROTECT(1);    /* no more need to protect */ 
    return result; 
} 

И вызывается из R с .Call("ranking_call", as.integer(ranking)).

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

+0

спасибо большое! Наверное, мне сначала нужно изучить немного более глубокие команды, правила и номенклатуру о динамических библиотеках C в R. Btw, с точки зрения эффективности и потребления памяти этот подход лучше, чем использование функции '.C' и избежать S-выражений? – Stefano

+0

Я не мог спросить лучшего ответа !! большое спасибо! – Stefano

+3

Излишне говорить, что Rcpp также a) использует '.Call()', b) экранирует вас от всех линейных шумов 'PROTECT()' и 'UNPROTECT()' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' добавляет обработку исключений, d) предоставляет инструменты для сборки, ... но некоторые люди действительно предпочитают C и делают всю дополнительную работу, и это совершенно нормально. Как сказал Камю, мы представляем себе Сизифа как счастливого человека ... –

6

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

Вы просили помощи у C. Я хотел бы предложить C++, который вам не нужно использовать сложным способом. Рассмотрим этот короткий файл с содержит функцию для обработки вектора вдоль линии вы предлагаете (я просто проверить для NA, а затем назначить 42 в качестве маркера для simplicit), либо квадрат значение:

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
NumericVector foo(NumericVector x) { 
    unsigned int n = x.size(); 
    for (unsigned int i=0; i<n; i++) 
     if (NumericVector::is_na(x[i])) 
      x[i] = 42.0; 
     else 
      x[i] = pow(x[i], 2); 
    return x; 
} 


/*** R 
foo(c(1, 3, NA, NaN, 6)) 
*/ 

Если я сохранить этот на моем поле, как /tmp/foo.cpp, в порядке компиляции, ссылки, нагрузки и даже запустить встроенный использовать R пример, мне нужно только одну строку для вызова sourceCpp():

R> Rcpp::sourceCpp("/tmp/foo.cpp") 

R> foo(c(1, 3, NA, NaN, 6)) 
[1] 1 9 42 42 36 
R> 

Мы можем сделать то же самое с целыми числами:

// [[Rcpp::export]] 
IntegerVector bar(IntegerVector x) { 
    unsigned int n = x.size(); 
    for (unsigned int i=0; i<n; i++) 
     if (IntegerVector::is_na(x[i])) 
      x[i] = 42; 
     else 
      x[i] = pow(x[i], 2); 
     return x; 
} 
+0

Всегда изысканный, чтобы получить _immediate_ downvotes, которые не имеют комментариев. Качественный товар. –

+0

Я на самом деле не сдул вам! Как я могу сделать! вы мне очень помогаете! Я постараюсь это изучить и понять (может быть, завтра, здесь почти полночь ...). Я уверен, что это поможет мне не только в этом вопросе! большое спасибо! – Stefano

+0

@ dirk в чем смысл предпочтения использовать синтаксический сахар Rcpp '** Vector :: is_na (x [i])' vs не использовать сахара 'IntegerVector [i] == NA_INTEGER'? Я склонен обнаруживать, что отладка более сложна при использовании сахара. –

Смежные вопросы