У меня есть решение, но оно не очень хорошо масштабируется:
findBiggestSubmatrixNonContiguous <- function(A) {
A <- !is.na(A); ## don't care about non-NAs
howmany <- expand.grid(nr=seq_len(nrow(A)),nc=seq_len(ncol(A)));
howmany <- howmany[order(apply(howmany,1L,prod),decreasing=T),];
for (ri in seq_len(nrow(howmany))) {
nr <- howmany$nr[ri];
nc <- howmany$nc[ri];
rcom <- combn(nrow(A),nr);
ccom <- combn(ncol(A),nc);
comcom <- expand.grid(ri=seq_len(ncol(rcom)),ci=seq_len(ncol(ccom)));
for (comi in seq_len(nrow(comcom)))
if (all(A[rcom[,comcom$ri[comi]],ccom[,comcom$ci[comi]]]))
return(list(ri=rcom[,comcom$ri[comi]],ci=ccom[,comcom$ci[comi]]));
}; ## end for
NULL;
}; ## end findBiggestSubmatrixNonContiguous()
Он основан на идее, что если матрица имеет достаточно малую плотность NA, то, выполнив поиск сначала самых больших подматриц, вы, скорее всего, найдете решение довольно быстро.
Алгоритм работает путем вычисления декартова произведения всех количеств строк и количеств столбцов, которые могут быть проиндексированы из исходной матрицы для получения подматрицы. Затем набор пар отсчетов упорядочивается по убыванию размера подматрицы, которая будет создана каждой парой отсчетов; другими словами, упорядоченный произведением двух счетов. Затем он перебирает эти пары. Для каждой пары он вычисляет все комбинации индексов строк и индексов столбцов, которые могут быть взяты для этой пары счетчиков, и пробует каждую комбинацию по очереди, пока не найдет подматрицу, содержащую нулевые NA. Найдя такую подматрицу, он возвращает этот набор индексов строк и столбцов в виде списка.
Результат гарантированно будет правильным, потому что он пробует размеры подматриц в порядке убывания, поэтому первая найденная должна быть самой большой (или привязанной к самой большой) возможной подматрице, которая удовлетворяет условию.
## OP's example matrix
A <- data.frame(C1=c(NA,NA,NA,NA,2L,NA),C2=c(1L,1L,1L,0L,NA,NA),C3=c(1L,8L,NA,1L,1L,NA),C4=c(NA,1L,1L,6L,1L,3L),C5=c(NA,1L,5L,1L,1L,NA),row.names=c('R1','R2','R3','R4','R5','R6'));
A;
## C1 C2 C3 C4 C5
## R1 NA 1 1 NA NA
## R2 NA 1 8 1 1
## R3 NA 1 NA 1 5
## R4 NA 0 1 6 1
## R5 2 NA 1 1 1
## R6 NA NA NA 3 NA
system.time({ res <- findBiggestSubmatrixNonContiguous(A); });
## user system elapsed
## 0.094 0.000 0.100
res;
## $ri
## [1] 2 3 4
##
## $ci
## [1] 2 4 5
##
A[res$ri,res$ci];
## C2 C4 C5
## R2 1 1 1
## R3 1 1 5
## R4 0 6 1
Мы видим, что функция работает очень быстро на примере матрицы OP и возвращает правильный результат.
randTest <- function(NR,NC,probNA,seed=1L) {
set.seed(seed);
A <- replicate(NC,sample(c(NA,0:9),NR,prob=c(probNA,rep((1-probNA)/10,10L)),replace=T));
print(A);
print(system.time({ res <- findBiggestSubmatrixNonContiguous(A); }));
print(res);
print(A[res$ri,res$ci,drop=F]);
invisible(res);
}; ## end randTest()
Я написал эту функцию, чтобы упростить тестирование. Мы можем вызвать его для проверки случайной входной матрицы размера NR
на NC
с вероятностью выбора NA в любой заданной ячейке probNA
.
Вот несколько тривиальных тестов:
randTest(8L,1L,1/3);
## [,1]
## [1,] NA
## [2,] 1
## [3,] 4
## [4,] 9
## [5,] NA
## [6,] 9
## [7,] 0
## [8,] 5
## user system elapsed
## 0.016 0.000 0.003
## $ri
## [1] 2 3 4 6 7 8
##
## $ci
## [1] 1
##
## [,1]
## [1,] 1
## [2,] 4
## [3,] 9
## [4,] 9
## [5,] 0
## [6,] 5
randTest(11L,3L,4/5);
## [,1] [,2] [,3]
## [1,] NA NA NA
## [2,] NA NA NA
## [3,] NA NA NA
## [4,] 2 NA NA
## [5,] NA NA NA
## [6,] 5 NA NA
## [7,] 8 0 4
## [8,] NA NA NA
## [9,] NA NA NA
## [10,] NA 7 NA
## [11,] NA NA NA
## user system elapsed
## 0.297 0.000 0.300
## $ri
## [1] 4 6 7
##
## $ci
## [1] 1
##
## [,1]
## [1,] 2
## [2,] 5
## [3,] 8
randTest(10L,10L,1/3);
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] NA NA 0 3 8 3 9 1 6 NA
## [2,] 1 NA NA 4 5 8 NA 8 2 NA
## [3,] 4 2 5 3 7 6 6 1 1 5
## [4,] 9 1 NA NA 4 NA NA 1 NA 9
## [5,] NA 7 NA 8 3 NA 5 3 7 7
## [6,] 9 3 1 2 7 NA NA 9 NA 7
## [7,] 0 2 NA 7 NA NA 3 8 2 6
## [8,] 5 0 1 NA 3 3 7 1 NA 6
## [9,] 5 1 9 2 2 5 NA 7 NA 8
## [10,] NA 7 1 6 2 6 9 0 NA 5
## user system elapsed
## 8.985 0.000 8.979
## $ri
## [1] 3 4 5 6 8 9 10
##
## $ci
## [1] 2 5 8 10
##
## [,1] [,2] [,3] [,4]
## [1,] 2 7 1 5
## [2,] 1 4 1 9
## [3,] 7 3 3 7
## [4,] 3 7 9 7
## [5,] 0 3 1 6
## [6,] 1 2 7 8
## [7,] 7 2 0 5
Я не знаю простого способа проверить правильность приведенного выше результата, но мне он кажется хорошим. Но для получения этого результата потребовалось почти 9 секунд. Запуск функции на матрицах среднего размера, особенно на матрице 77x132, вероятно, является безнадежным делом.
Ожидание, может ли кто-нибудь придумать блестящее эффективное решение...
person
bgoldst
schedule
07.04.2016
A[c(2,4,5),3:5]
не лучшее решение с 9 ячейками? - person bgoldst   schedule 07.04.2016A[2:4, c(2, 4, 5)]
- person MichaelChirico   schedule 07.04.2016NA
s ... но также озадачены этим - person MichaelChirico   schedule 07.04.2016