2015-02-06 4 views
4

Я хотел бы создать все возможные комбинации двоичного вектора, выполненного из фиксированного числа 0 и 1. Например: dim (v) = 5x1; n1 = 3; n0 = 2; В этом случае я хотел бы иметь что-то вроде:Создание комбинаций двоичного вектора

1,1,1,0,0 
    1,1,0,1,0 
    1,1,0,0,1 
    1,0,1,1,0 
    1,0,1,0,1 
    1,0,0,1,1 
    0,1,1,1,0 
    0,1,1,0,1 
    0,1,0,1,1 
    0,0,1,1,1 

Я нашел некоторую помощь читать этот пост Create all possible combiations of 0,1, or 2 "1"s of a binary vector of length n , но я хотел бы, чтобы генерировать только комбинацию мне нужно избегать любых отходов пространства (я думаю, что проблема будет explonentially возрастать с п)

+3

не столь эффективный подход будет 'х <- expand.grid (респ (список (0L: 1L), 5л)); x [rowSums (x) == 3L,] ', но я думаю, вы хотите что-то быстрее, чем это. –

+0

Следующие могут помочь: http://stackoverflow.com/questions/17292091/rbinary-matrix-for-all-possible-unique-results –

ответ

5

Немного более быстрый вариант ответа Марата:

f.roland <- function(n, m) { 
    ind <- combn(seq_len(n), m) 
    ind <- t(ind) + (seq_len(ncol(ind)) - 1) * n 
    res <- rep(0, nrow(ind) * n) 
    res[ind] <- 1 
    matrix(res, ncol = n, nrow = nrow(ind), byrow = TRUE) 
} 

all.equal(f.2(16, 8), f.roland(16, 8)) 
#[1] TRUE 
library(rbenchmark) 
benchmark(f(16,8),f.2(16,8),f.roland(16,8)) 

#    test replications elapsed relative user.self sys.self user.child sys.child 
#2  f.2(16, 8)   100 5.693 1.931  5.670 0.020   0   0 
#3 f.roland(16, 8)   100 2.948 1.000  2.929 0.017   0   0 
#1  f(16, 8)   100 8.287 2.811  8.214 0.066   0   0 
+0

По какой-то причине я не могу воспроизвести результаты тестирования: мой бенчмаркинг говорит, что' f.2' и 'f.roland' имеют примерно одинаковые (в пределах ~ 1%). Не могли бы вы повторить бенчмаркинг пару раз, чтобы убедиться, что результаты согласованы? –

+0

И для полноты вы могли бы включить другие функции в бенчмаркинг? –

+0

@MaratTalipov Я повторил тесты и получил тот же результат. Невозможно включить функцию akrun, так как я не хочу устанавливать биокондуктор. – Roland

4

Вы можете попробовать этот подход:

f <- function(n=5,m=3) 
t(apply(combn(1:n,m=m),2,function(cm) replace(rep(0,n),cm,1))) 

f(5,3) 
#  [,1] [,2] [,3] [,4] [,5] 
# [1,] 1 1 1 0 0 
# [2,] 1 1 0 1 0 
# [3,] 1 1 0 0 1 
# [4,] 1 0 1 1 0 
# [5,] 1 0 1 0 1 
# [6,] 1 0 0 1 1 
# [7,] 0 1 1 1 0 
# [8,] 0 1 1 0 1 
# [9,] 0 1 0 1 1 
# [10,] 0 0 1 1 1 

идея заключается в том, чтобы генерировать все комбинации индексов на 1, а затем к и чтобы получить конечный результат.

Другой вкус одного и того же подхода:

f.2 <- function(n=5,m=3) 
    t(combn(1:n,m,FUN=function(cm) replace(rep(0,n),cm,1))) 

Второй подход заключается примерно в два раза быстрее:

library(rbenchmark) 
benchmark(f(16,8),f.2(16,8)) 
#   test replications elapsed relative user.self sys.self user.child sys.child 
# 2 f.2(16, 8)   100 5.706 1.000  5.688 0.017   0   0 
# 1 f(16, 8)   100 10.802 1.893 10.715 0.082   0   0 

Тест

f.akrun <- function(n=5,m=3) { 

    indx <- combnPrim(1:n,m) 

    DT <- setDT(as.data.frame(matrix(0, ncol(indx),n))) 
    for(i in seq_len(nrow(DT))){ 
    set(DT, i=i, j=indx[,i],value=1) 
    } 
    DT 
} 

benchmark(f(16,8),f.2(16,8),f.akrun(16,8)) 
#   test replications elapsed relative user.self sys.self user.child sys.child 
# 2  f.2(16, 8)   100 5.464 1.097  5.435 0.028   0   0 
# 3 f.akrun(16, 8)   100 4.979 1.000  4.938 0.037   0   0 
# 1  f(16, 8)   100 10.854 2.180 10.689 0.129   0   0 

@ раствора akrun в (f.akrun) составляет ~ 10 % быстрее, чем f.2.

[EDIT] Другой подход, который является еще более быстрым и простым:

f.3 <- function(n=5,m=3) t(combn(n,m,tabulate,nbins=n)) 
+0

Я очень ценю вашу помощь! –

+0

'f.3' является лучшим, недостаточно выделенным imo ;-) – Cath

1

Вы можете попробовать combnPrim из gRbase вместе с set из data.table (который может быть faster)

source("http://bioconductor.org/biocLite.R") 
biocLite("gRbase") 
library(gRbase) 
library(data.table) 
n <-5 
indx <- combnPrim(1:n,3) 

DT <- setDT(as.data.frame(matrix(0, ncol(indx),n))) 
for(i in seq_len(nrow(DT))){ 
    set(DT, i=i, j=indx[,i],value=1) 
} 
DT 
# V1 V2 V3 V4 V5 
#1: 1 1 1 0 0 
#2: 1 1 0 1 0 
#3: 1 0 1 1 0 
#4: 0 1 1 1 0 
#5: 1 1 0 0 1 
#6: 1 0 1 0 1 
#7: 0 1 1 0 1 
#8: 1 0 0 1 1 
#9: 0 1 0 1 1 
#10: 0 0 1 1 1 
0

Вот другой подход:

func <- function(n, m) t(combn(n, m, function(a) {z=integer(n);z[a]=1;z})) 

func(n = 5, m = 2) 

    # [,1] [,2] [,3] [,4] [,5] 
# [1,] 1 1 0 0 0 
# [2,] 1 0 1 0 0 
# [3,] 1 0 0 1 0 
# [4,] 1 0 0 0 1 
# [5,] 0 1 1 0 0 
# [6,] 0 1 0 1 0 
# [7,] 0 1 0 0 1 
# [8,] 0 0 1 1 0 
# [9,] 0 0 1 0 1 
# [10,] 0 0 0 1 1 
Смежные вопросы