Сколько векторов можно добавить в DataFrame::create( vec1, vec2 ...)?

Я создаю DataFrame для хранения разобранных файлов журнала http haproxy, который имеет довольно много полей (25+).

Если я добавлю более 20 векторов (по одному на каждое поле), я получу ошибку компиляции:

no matching function call to 'create'

Метод создания:

    return DataFrame::create(
      _["clientIp"]     = clientIp,
      _["clientPort"]   = clientPort,
      _["acceptDate"]   = acceptDate,
      _["frontendName"] = frontendName,
      _["backendName"]  = backendName,
      _["serverName"]   = serverName,
      _["tq"]           = tq,
      _["tw"]           = tw,
      _["tc"]           = tc,
      _["tr"]           = tr,
      _["tt"]           = tt,
      _["status_code"]  = statusCode,
      _["bytes_read"]   = bytesRead,

#if CAPTURED_REQUEST_COOKIE_FIELD == 1
      _["capturedRequestCookie"]   = capturedRequestCookie,
#endif     

#if CAPTURED_REQUEST_COOKIE_FIELD == 1
      _["capturedResponseCookie"]   = capturedResponseCookie,
#endif    

      _["terminationState"] = terminationState,
      _["actconn"]          = actconn,
      _["feconn"]           = feconn,
      _["beconn"]           = beconn,
      _["srv_conn"]         = srvConn,
      _["retries"]          = retries,
      _["serverQueue"]      = serverQueue,
      _["backendQueue"]     = backendQueue 
    );

Вопросы:

  1. Я достиг жесткого предела?
  2. Есть ли обходной путь, позволяющий мне добавить более 20 векторов во фрейм данных?

2 ответа

Решение

Да, вы достигли жесткого предела - Rcpp ограничено стандартом C++98, который требует явного раздувания кода для поддержки аргументов 'variadic'. По сути, новая перегрузка должна быть сгенерирована для каждого create Используемая функция, и чтобы не задушить компилятор Rcpp просто обеспечивает до 20.

Обходным путем будет использование класса "строитель", где вы последовательно добавляете элементы, а затем конвертируете в DataFrame в конце. Простой пример такого класса - мы создаем ListBuilder объект, для которого мы последовательно add новые столбцы. Попробуйте запустить Rcpp::sourceCpp() с этим файлом, чтобы увидеть вывод.

#include <Rcpp.h>
using namespace Rcpp;

class ListBuilder {

public:

   ListBuilder() {};
   ~ListBuilder() {};

   inline ListBuilder& add(std::string const& name, SEXP x) {
      names.push_back(name);

      // NOTE: we need to protect the SEXPs we pass in; there is
      // probably a nicer way to handle this but ...
      elements.push_back(PROTECT(x));

      return *this;
   }

   inline operator List() const {
      List result(elements.size());
      for (size_t i = 0; i < elements.size(); ++i) {
         result[i] = elements[i];
      }
      result.attr("names") = wrap(names);
      UNPROTECT(elements.size());
      return result;
   }

   inline operator DataFrame() const {
      List result = static_cast<List>(*this);
      result.attr("class") = "data.frame";
      result.attr("row.names") = IntegerVector::create(NA_INTEGER, XLENGTH(elements[0]));
      return result;
   }

private:

   std::vector<std::string> names;
   std::vector<SEXP> elements;

   ListBuilder(ListBuilder const&) {}; // not safe to copy

};

// [[Rcpp::export]]
DataFrame test_builder(SEXP x, SEXP y, SEXP z) {
   return ListBuilder()
      .add("foo", x)
      .add("bar", y)
      .add("baz", z);
}

/*** R
test_builder(1:5, letters[1:5], rnorm(5))
*/

PS: с Rcpp11, у нас есть переменные функции и, следовательно, ограничения сняты.

Другой распространенный подход с Rcpp - это просто использовать внешний список, содержащий столько объектов DataFrame (каждый из которых ограничен количеством элементов, предоставляемых посредством расширения / повторения макросов старой школы) в соответствующем заголовке), сколько вам нужно.

В (не проверенном) коде:

Rcpp::DataFrame a = Rcpp::DateFrame::create(/* ... */);
Rcpp::DataFrame b = Rcpp::DateFrame::create(/* ... */);
Rcpp::DataFrame c = Rcpp::DateFrame::create(/* ... */);

return Rcpp::List::create(Rcpp::Named("a") = a,
                          Rcpp::Named("b") = b,
                          Rcpp::Named("c") = c);
Другие вопросы по тегам