2012-06-05 2 views
0

Имея некоторые головные боли в строках обработки Rcpp, посмотрели на «Как протестировать Rcpp :: CharacterVector элементы для равенства», но ситуация немного сложнее.Rcpp: опрятный способ сравнения строк, полученных из кадра данных R?

Для иллюстрации предположим, что у нас есть кадр данных 200-строк имен и знаков, генерируемых случайным образом:

df = data.frame(name = paste("Person", 
          sample(LETTERS[1:10],200,rep=TRUE),sep=""), 
       mark = pmax(pmin(round(rnorm(200,60,15)),100),0), 
       stringsAsFactors=FALSE) 

Я обнаружил, что следующий встроенный код (с помощью Rcpp) корректно отрабатывает сумму знаков для всех строк, где человек по имени является первым человеком, дан в кадре данных (т.е. ДФ $ имя [1] в R, или, что эквивалентно имя [0] в коде Rcpp):

library(inline) 

fastfunc_good1 <- cxxfunction(
    signature(DFin = "data.frame"), 
    plugin = "Rcpp", 
    body = ' 
     Rcpp::DataFrame DF(DFin); 
     Rcpp::CharacterVector name = DF["name"]; 
     Rcpp::IntegerVector mark = DF["mark"]; 
     Rcpp::CharacterVector targetname(1); 
     Rcpp::CharacterVector thisname(1);  

     int n = name.length(); 
     int tot = 0; 
     targetname = name[0]; 
     std::string s_targetname = as<std::string>(targetname); 

     for (int i = 0; i < n; i++) { 
      thisname=name[i]; 
      std::string s_thisname = as<std::string>(thisname); 
      if (s_thisname == s_targetname) { 
       tot = tot + mark[i]; 
      } 
     } 

     return(Rcpp::wrap(tot)); 
     ') 

Теперь я действительно хотят упростить это как можно больше, так как это грязно, чтобы определить отдельную переменную для повторного представить значение в имени [], принудить к std :: string, а затем выполнить сравнение. Там должен каким-то образом упрощения обозначений, так это больше похоже на следующее (что следует отметить, НЕ РАБОТАЕТ!) ...

fastfunc_bad1 <- cxxfunction(
    signature(DFin = "data.frame"), 
    plugin = "Rcpp", 
    body = ' 
     Rcpp::DataFrame DF(DFin); 
     Rcpp::CharacterVector name = DF["name"]; 
     Rcpp::IntegerVector mark = DF["mark"]; 

     int n = name.length(); 
     int tot = 0; 

     for (int i = 0; i < n; i++) { 
      if (name[i] == name[0]) { 
       tot = tot + mark[i]; 
      } 
     } 

     return(Rcpp::wrap(tot)); 
     ') 

В конечном счете, цель этого мини-проекта обучения для меня, чтобы выяснить, как перебирать уникальные имена в df $ name, вычислять сумму метки для каждого из них и возвращать все (уникальные имена и соответствующие суммы) в качестве аккуратного фрейма данных. Я вычислил большинство гаек и болтов о том, как создавать и возвращать окончательный фрейм данных из других примеров - это всего лишь строка, описанная выше, которая вызывает у меня головные боли. Большое спасибо заранее за любые указатели!

ответ

4

Вы можете использовать Rcpp :: для преобразования объектов R в контейнеры C++. Для меня работает следующее.

fastfunc_good2 <- cxxfunction(
    signature(DFin = "data.frame"), 
    plugin = "Rcpp", 
    body = ' 
     Rcpp::DataFrame DF(DFin); 
     std::vector<std::string> name = Rcpp::as<std::vector<std::string> >(DF["name"]); 
     std::vector<int> mark = Rcpp::as<std::vector<int> >(DF["mark"]); 

     int n = name.size(); 
     int tot = 0; 

     for (int i = 0; i < n; i++) { 
      if (name[i] == name[0]) { 
       tot = tot + mark[i]; 
      } 
     } 

     return(Rcpp::wrap(tot)); 
     ') 


> fastfunc_good1(df) 
[1] 1040 

> fastfunc_good2(df) 
[1] 1040 
+0

Спасибо. Странно, что IntegerVector поддерживает простые операции, подобные этому, но CharacterVector этого не делает. Есть ли короткий путеводитель, где объясняется, какие основные операции не работают на CharacterVector/IntegerVector и, следовательно, требуют такого рода преобразования? Или должен ли первый шаг в коде Rcpp всегда переназначать данные на переменные C++ перед использованием? –

+0

В качестве продолжения (немного слишком отрывочного сейчас, чтобы перейти к полному вопросу, поскольку я обдумываю его) ... Какова нынешняя лучшая практика с точки зрения использования кадров данных в Rcpp? Легкость, с которой можно «перехватить» кадр данных из R, очень аккуратная, но если в кадре данных имеется n столбцов, то считается, что данные должны быть разделены на n отдельных (C++) векторов перед использованием? В приведенном выше примере предлагается «да», поскольку, похоже, не поддерживается нотация, такая как df.name [i]. Но если ответ «да», значит ли это, что подмножество должно выполняться неявно, через логические векторы говорят? –

+0

только один простой вопрос здесь, DF ["name"] возврат вектора или dataframe? потому что мы используем drop = TRUE right, если только один столбец подмножественно –

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