#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. Итак, похоже, мне не нужно сдвигать индексы. Спасибо за разъяснение!