2017-02-09 13 views
1

以下のように文字データを数値に変換しようとしています。データには特別なキャラクターが付いてくるので、私はそれらを出さなければならない。私はデータをstd:stringに変換して特殊キャラクターを検索します。それはメモリ内に新しい変数を作成しますか?私はそれを行うより良い方法があるかどうかを知りたい。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" 

*/ 

私はそれを行うには良い方法があるかどうかを知りたいです。

まず最初に、 "より良い" を定義する必要があります。

  • より速いですか?
  • メモリを少なくしますか?
  • コードの数が少なくて済みますか?
  • もっと慣用ですか?

個人的には、私は最後の定義から始めようとしますが、それはしばしば他のものの1つ以上を伴うからです。例えば、このアプローチでは、我々は

  • ではなく、ローカルに
  • は、によって決定される文字を排除するためにerase-remove idiomを使用する別の関数オブジェクトを定義し、これを実装しようとしているよりも、標準ライブラリ関数isdigitに依存している関数オブジェクトPredicateを定義しますPredicate;そして、必要に応じて、(代わりにこの身を実装しようと、再び)doubleに残るものに変換するstd::atoiを使用しています
  • は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; 
} 

テ最小限の機能のために刺さこの、

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