Есть ли способ исключить строки и столбцы из массива C ?

#c #arrays #c 11 #rcpp

#c #массивы #c 11 #rcpp

Вопрос:

Предположим, у меня есть массив на C , такой как следующий:

 1  2  3  4 = arr
5  6  7  8
9  9  8  9
7  6  1  3
  

Есть ли краткий способ исключить любую строку и / или столбец?

Например, предположим, что я хочу выполнить операцию со следующим массивом:

 1  3  4
5  7  8
7  1  3
  

На других языках программирования я могу довольно легко получить приведенный выше массив с помощью arr[-3,-2], чтобы исключить третью строку и второй столбец. Однако мне не удалось найти краткий способ исключения строк и столбцов в C . Как бы вы это сделали?

Обновить:

Я полагаю, что это проблема XY. Позвольте мне рассказать вам, почему я хочу это сделать.

Я использую статистическую модель, в частности модель условной авторегрессии (CAR). В этой модели Гаусса нам нужна функция среднего значения и ковариационная матрица.

Мы получаем среднюю функцию как

среднее значение = mu Sig(i,-i) * inv(Sig(-i,-i)) * (v(i,-i) — mu)

и ковариационная матрица в виде

s2 = Sig(i,i) — Sig(i,-i) * inv(Sig(-i,-i)) * Sig(-i,i)

Итак, мне нужно получить три варианта матрицы Sig: Sig(l,-l), Sig(-l,-l), Sig(-l,l). Вот почему я надеюсь найти простой способ исключить строки и столбцы. Обычно я бы запрограммировал это на R, но это занимает так много времени. Итак, я надеюсь заставить его работать в Rcpp.

Следующее обновление:

Я думаю, что я это выясняю, поэтому спасибо комментаторам. Это то, о чем я думаю. Мне нужен вектор, который хранит индексы, которые я хочу сохранить в своей подматрице. Я планирую использовать функцию X.submat() Rcpp.

Предположим, я хочу получить подматрицу Sig, которая исключает i-ю строку и i-й столбец. Тогда у меня должен быть вектор индексов, содержащий {0,1,…, (i-2),i,…, (L-1)}, поскольку индексация C начинается с 0. Чтобы получить этот вектор индексов, у меня есть следующий код:

 // We need to get the vector of indices excluding i
  arma::vec vece = arma::zeros(L-1); // vector to exclude the ith index
  for(int k = 0; k < (L-1); k  ){ // we have a vector of length L-1
    if(k < (i-1)){
      vece(k)=k;
    }
    else if(k == (i-1)){
      // do not add the ith index
    }
    else{ // k > (i-1)
      vece(k-1) = k;
    }
  }
  
  // We need to make Sig(-i,-i)
  arma::mat Sigee = arma::zeros(L-1,L-1); // ee for exclude,exclude
  Sigee = Sig.submat(vece,vece)
  

Однако, похоже, это не работает, когда i = 0. У меня есть этот код в следующем цикле for, поэтому мне нужно, чтобы это работало, когда i = 0.

 for(int l = 0; l < L; l  ){                     }
  

Комментарии:

1. Есть ли краткий способ исключить любую строку и / или столбец? — Звучит как проблема XY .

2. Вероятно, это можно сделать с помощью представлений диапазона en.cppreference.com/w/cpp/ranges . Но лучше всего было бы, чтобы OP описал свои конечные цели

3. Вы можете попробовать косвенное обращение. Пусть другой массив обозначает индексы, которые вы хотите обработать, и выполняет цикл по этому массиву, т. Е. array[index[i]] вместо array[i] . Я не удивлюсь, если именно так это делают другие языки.

4. Можете ли вы использовать какую-нибудь библиотеку для линейной алгебры? Например, Eigen — тогда вы можете просто нарезать, инвертировать, умножать и т.д.

5.Поскольку ваш другой вопрос помечен rcpparmadillo , вы можете захотеть взглянуть на отличные документы Armadillo. В частности, ссылка, которую я даю там, относится к теме «представления подматрицы». Вы можете посмотреть на .submat() метод, который по существу использует косвенный подход, упомянутый @PaulMcKenzie, Это несколько стандартная плата за проезд Armadillo

Ответ №1:

Мне кажется, что более простым подходом является заполнение n-1 длины uvec последовательными целыми числами, просто пропуская i , вот так:

 // [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>

// [[Rcpp::export]]
arma::mat exclude_one_row_and_col(const arma::matamp; X, arma::uword i) {
    arma::uword n = X.n_rows; // X should be square so only need # rows
    arma::uvec idx(n-1); // vector of indices to subset by
    arma::uword ii = 0; // the integer we'll add at each elem of idx
    for ( arma::uword j = 0; j < (n-1);   j ) { // for each elem of idx
        if ( ii == i ) { // if ii equals i, we need to skip i
            ii  = 1;     // (i.e., add 1 to ii)
        }
        idx[j] = ii;     // then we store ii for this elem
        ii  = 1;         // and increment ii
    }
    return X.submat(idx, idx); // finally we can subset the matrix
}
  

Простая демонстрация показывает, что это работает так, как ожидалось:

 X <- diag(1:3)
X
#      [,1] [,2] [,3]
# [1,]    1    0    0
# [2,]    0    2    0
# [3,]    0    0    3

exclude_one_row_and_col(X, 0)
#      [,1] [,2]
# [1,]    2    0
# [2,]    0    3

exclude_one_row_and_col(X, 1)
#      [,1] [,2]
# [1,]    1    0
# [2,]    0    3

exclude_one_row_and_col(X, 2)
#      [,1] [,2]
# [1,]    1    0
# [2,]    0    2
  

Комментарии:

1. Это работает отлично — спасибо! Только один последующий вопрос: работает ли индексация в Rcpp:: functions как C или R? Позвольте мне объяснить это немного подробнее. Мы знаем, что индексация R начинается с 1, а C — с 0. Итак, предположим, что я хочу вызвать Rcpp::qnorm(p(i)) в Cpp. Ну, i начинается с 0, поэтому i, естественно, отстает от правильного индекса в R. Когда я вызываю Rcpp::qnrom(p (i)), если я хочу получить относительно правильное значение, должен ли я вместо этого вызвать Rcpp::qnorm(p(i 1)), чтобы исправить сдвиг в индексации? Или Rcpp автоматически корректирует сдвиг в индексации?

2. @RonSnow Написание C с использованием функций Rcpp или RcppArmadillo работает так же, как и любой другой C , 0-индексация и все

3. Итак, похоже, мне не нужно сдвигать индексы. Спасибо за разъяснение!