Перебирать векторы из импортированного информационного кадра по строкам - PullRequest
0 голосов
/ 07 января 2019

Я пытаюсь переключиться с кодирования R на c ++. Если вы решите проголосовать за этот вопрос, по крайней мере, покровительствуйте мне ответом, чтобы я мог кое-что выучить. Мой вопрос заключается в том, как я должен подходить к строковым вычислениям в c ++ после того, как я передал c ++ фрейм данных? Концептуально я понимаю, что как только я передам c ++ фрейм данных, c ++ будет обрабатывать каждый столбец как свой собственный вектор, который я должен явно назвать. Когда у меня возникают проблемы, я настраиваю цикл for для итерации по одной и той же позиции всех векторов одновременно, таким образом, функционально эмулируя построчную функцию в R. Я хотел бы распространить этот вопрос также на следующие приложения:

  1. Как бы я создал цикл, который повторяется по строке и возвращает вектор. Как Rowsum в R? Есть пример этого в расширенном R, использующем матрицу, но номенклатура не переводится в векторы кучи из кадра данных.
  2. Как бы настроить цикл, который выполняет итерацию по строке, изменяет значения в каждой строке и возвращает измененные векторы?
  3. Как бы я создал цикл, который выполняет итерацию по ряду строк одновременно, создавая функцию скользящего окна? как это:

    ## an example of a for loop in R that I want to recapitulate in c++
    output <- list() 
    
    for(i in 1:nrow(df)){
      end_row <- i+3
      df_tmp <- df[i:end_row, ]
      ## do some function here
      output[[i]] <- list(df_tmp)
    }
    
  4. Как бы я настроил ту же функцию прокрутки в вопросе 3, но таким образом, чтобы я мог условно увеличить длину вектора? В R я написал функции, использующие apply, которые выполняют итерацию по диапазону строк, а затем возвращают список новых фреймов данных, которые я затем превращаю в большой фрейм данных. Выполнение этого одного вектора за один раз концептуально озадачивает меня в настоящий момент.

Допустим, у меня есть этот кадр данных в R

#example data    
a <- c(0, 2, 4, 6, 8, 10)
b <- c(1, 3, 5, 7, 9, 11)
c <- c("chr1", "chr1", "chr1", "chr1", "chr1", "chr1")
d <- c(10.2, 10.2, 4.3, 4.3, 3.4, 7.9)
e <- c("a", "t", "t", "g", "c", "a")

df <- data.frame(a, b, c, d, e)

В C ++ я получил это далеко:

#include <algorithm>
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
DataFrame modifyDataFrame(DataFrame df) {

  // access the columns
  IntegerVector a = df["a"];
  IntegerVector b = df["b"];
  CharacterVector c = df["c"];
  IntegerVector d = df["d"];
  CharacterVector e = df["e"];

// write the for loop. I'm attempting to define a single
//position and then apply it to all vectors... 
//but no versions of this approach have worked.   

  for(int i=0; i < a.length(); ++i){

  // do some function
  }
  // return a new data frame
  return DataFrame::create(_["a"]= a, _["b"]= b, _["c"]= c, _["d"]= d, _["e"]=e);
}

Я следил за разделом Advanced R по этому вопросу. Часть, которую я изо всех сил пытаюсь понять, - это построение нескольких векторов с четырьмя петлями, и как определить мои итераторы диапазона. Исходя из моего кода, это тоже ваша интерпретация? Нужно ли создавать итератор для каждого вектора или я могу просто определить одну позицию на основе длины одного вектора и затем применить ко всем векторам?

Самый простой способ для меня пройти мимо этого - это посмотреть пример. Когда я увижу пример функционального кода, я смогу применить концепции, о которых я читал.

Редактировать: возможно ли добавить несколько подобных примеров в документацию RCPP? Я думаю, что многие люди борются на этом этапе. Учитывая, что информационный фрейм является одним из наиболее распространенных r-контейнеров данных, я думаю, что документация rcpp будет значительно усилена еще парой примеров фреймов данных - концептуальное переключение не является тривиальным на первый взгляд.

1 Ответ

0 голосов
/ 07 января 2019

Я не уверен, что вы добьетесь производительности, перейдя на C ++ здесь. Однако, если у вас есть набор векторов одинаковой длины (data.frame гарантирует это), вы можете просто выполнить итерацию с одним индексом:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
DataFrame modifyDataFrame(DataFrame df) {

  // access the columns
  IntegerVector a = df["a"];
  IntegerVector b = df["b"];
  CharacterVector c = df["c"];
  NumericVector d = df["d"];
  CharacterVector e = df["e"];

  for(int i=0; i < df.nrow(); ++i){
    a(i) += 1;
    b(i) += 2;
    c(i) += "c";
    d(i) += 3;
    e(i) += "e";
  }
  // return a new data frame
  return DataFrame::create(_["a"]= a, _["b"]= b, _["c"]= c, _["d"]= d, _["e"]=e);
}
/*** R
a <- c(0, 2, 4, 6, 8, 10)
b <- c(1, 3, 5, 7, 9, 11)
c <- c("chr1", "chr1", "chr1", "chr1", "chr1", "chr1")
d <- c(10.2, 10.2, 4.3, 4.3, 3.4, 7.9)
e <- c("a", "t", "t", "g", "c", "a")

df <- data.frame(a, b, c, d, e)
modifyDataFrame(df)  
*/

Результат:

> modifyDataFrame(df)  
   a  b     c    d  e
1  1  3 chr1c 13.2 ae
2  3  5 chr1c 13.2 te
3  5  7 chr1c  7.3 te
4  7  9 chr1c  7.3 ge
5  9 11 chr1c  6.4 ce
6 11 13 chr1c 10.9 ae

Здесь я использую метод nrow() класса DataFrame, c.f. API Rcpp . При этом используется R API C, как и метод length(). Я просто считаю более логичным использовать метод DataFrame, чем выделять один из векторов для получения длины. Результат будет таким же.

Что касается скользящего окна, я бы сначала посмотрел на пакет RcppRoll.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...