2017-02-09 2 views
1

Я пытаюсь преобразовать некоторые символьные данные в числовые, как показано ниже. Данные придут со специальными персонажами, поэтому я должен их вытащить. Я конвертирую данные в std: string для поиска специальных символов. Dos создает новую переменную в памяти? Я хочу знать, есть ли лучший способ сделать это.Управление памятью Rcpp

NumericVector converter_ra_(Rcpp::RObject x){ 
    if(x.sexp_type() == STRSXP){ 
    CharacterVector y(x); 
    NumericVector resultado(y.size()); 
    for(unsigned int i = 0; i < y.size(); i++){ 
     std::string ra_string = Rcpp::as<std::string>(y[i]); 
     //std::cout << ra_string << std::endl; 
     double t = 0; 
     int base = 0; 
     for(int j = (int)ra_string.size(); j >= 0; j--){ 
     if(ra_string[j] >= 48 && ra_string[j] <= 57){ 
      t += ((ra_string[j] - '0') * base_m[base]); 
      base++; 
     } 
     } 
     //std::cout << t << std::endl; 
     resultado[i] = t; 
    } 
    return resultado; 
    }else if(x.sexp_type() == REALSXP){ 
    return NumericVector(x); 
    } 
    return NumericVector(); 
} 
+2

Сначала добавьте образец данных, используя 'dput (data_set_here)'. Во-вторых, да. Вы собираетесь выделить новый вектор памяти, если тип не является «NumericVector». – coatless

ответ

4

ли она создает новую переменную в памяти?

Если входной объект фактически является числовым вектором (REALSXP), и вы просто возвращаетесь, например. as<NumericVector>(input), то никакие дополнительные переменные не создаются. В любом другом случае новая память, конечно, должна быть выделена для возвращаемого объекта. Например,

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
NumericVector demo(RObject x) { 
    if (x.sexp_type() == REALSXP) { 
     return as<NumericVector>(x); 
    } 

    return NumericVector::create(); 
} 

/*** R 

y <- rnorm(3) 
z <- letters[1:3] 

data.table::address(y) 
# [1] "0x6828398" 

data.table::address(demo(y)) 
# [1] "0x6828398" 

data.table::address(z) 
# [1] "0x68286f8" 

data.table::address(demo(z)) 
# [1] "0x5c7eea0" 

*/ 

Я хочу знать, если есть лучший способ сделать это.

Прежде всего, необходимо определить "лучше":

  • быстрее?
  • Использует меньше памяти?
  • Меньше строк кода?
  • Более идиоматический?

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

  • Определим функцию объекта Predicate, который зависит от стандартной библиотечной функции isdigit, а не пытаться осуществить это локально
  • Определить другой функциональный объект, который использует erase-remove idiom для устранения символов, как определено Predicate; и в случае необходимости, использует std::atoi преобразовать то, что остается в double (опять же, вместо того, чтобы пытаться реализовать это сам)
  • Использует Rcpp идиомы - as конвертера - для преобразования STRSXP до std::vector<std::string>
  • звонков std::transform чтобы преобразовать это в результате вектор

#include <Rcpp.h> 
using namespace Rcpp; 

struct Predicate { 
    bool operator()(char c) const 
    { return !(c == '.' || std::isdigit(c)); } 
}; 

struct Converter { 
    double operator()(std::string s) const { 
     s.erase(
      std::remove_if(s.begin(), s.end(), Predicate()), 
      s.end() 
     ); 

     return s.empty() ? NA_REAL : std::atof(s.c_str()); 
    } 
}; 

// [[Rcpp::export]] 
NumericVector convert(RObject obj) { 
    if (obj.sexp_type() == REALSXP) { 
     return as<NumericVector>(obj); 
    } 
    if (obj.sexp_type() != STRSXP) { 
     return NumericVector::create(); 
    } 

    std::vector<std::string> x = as<std::vector<std::string> >(obj); 
    NumericVector res(x.size(), NA_REAL); 

    std::transform(x.begin(), x.end(), res.begin(), Converter()); 
    return res; 
} 

Testing это для минимальной функциональности,

x <- c("123 4", "abc 1567.35 def", "abcdef", "") 
convert(x) 
# [1] 1234.00 1567.35  NA  NA 

(y <- rnorm(3)) 
# [1] 1.04201552 -0.08965042 -0.88236960 

convert(y) 
# [1] 1.04201552 -0.08965042 -0.88236960 

convert(list()) 
# numeric(0) 

Будет ли это быть производительным, как-то рука, написанная опытным C или C++ программист? Почти наверняка нет. Однако, поскольку мы использовали библиотечные функции и общие идиомы, он достаточно краток, скорее всего, будет без ошибок, и намерение довольно очевидно даже при быстром взгляде.Если вам нужно что-то быстрее, то, вероятно, потребуется несколько оптимизаций, но сначала не нужно начинать с этой предпосылки без бенчмаркинга и профилирования.

+0

Как насчет этой строки: std :: string ra_string = Rcpp :: as (y [i]); Когда я получаю STRSXP, я конвертирую его в std: string. Это стоит больше памяти? Действительно благодарю вас за ответ. – Gustavo

+0

Да при вызове 'Rcpp :: as ' потребуется выделить память для 'std :: string'. В общем случае любое преобразование между типами потребует выделения памяти для типа, к которому вы конвертируете. Единственная причина, по которой это не происходит с 'Rcpp :: as (REALSXP)', - это потому, что 'NumericVector' по существу является только классом-оболочкой, хранящим' REALSXP' внутри. – nrussell

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