Karakter vektör rasgele örnek, birbiri önek olmadan
(Sıfır-sıfır) max_len
basamaklı ikili sayılar olan bir karakter vektör, pool
, düşünün.
max_len <- 4
pool <- unlist(lapply(seq_len(max_len), function(x)
do.call(paste0, expand.grid(rep(list(c('0', '1')), x)))))
pool
## [1] "0" "1" "00" "10" "01" "11" "000" "100" "010" "110"
## [11] "001" "101" "011" "111" "0000" "1000" "0100" "1100" "0010" "1010"
## [21] "0110" "1110" "0001" "1001" "0101" "1101" "0011" "1011" "0111" "1111"
İsterim örnek n
Bu elemanları, kısıtlama yok ve numune elemanları prefixes herhangi bir diğer örnek elemanları (Yani eğer biz örnek 1101
biz ban 1
, 11
110
iken, eğer biz örnek 1
biz ban bu öğelerin başında 1
gibi 10
, 11
, 100
, vb.).
Aşağıdaki n
büyük (veya 2^max_len
yaklaştığında) benim girişimi while
ama tabii ki bu yavaş kullanıyor.
set.seed(1)
n <- 10
chosen <- sample(pool, n)
while(any(rowSums(outer(paste0('^', chosen), chosen, Vectorize(grepl))) > 1)) {
prefixes <- rowSums(outer(paste0('^', chosen), chosen, Vectorize(grepl))) > 1
pool <- pool[rowSums(Vectorize(grepl, 'pattern')(
paste0('^', chosen[!prefixes]), pool)) == 0]
chosen <- c(chosen[!prefixes], sample(pool, sum(prefixes)))
}
chosen
## [1] "0100" "0101" "0001" "0011" "1000" "111" "0000" "0110" "1100" "0111"
Bu biraz başlangıçta pool
yetersiz elemanlar pool
kalmadı boyutu toplam örnek almak n
demek olan bu öğeleri kaldırarak geliştirilebilir. E. g., max_len = 4
n > 9
, biz derhal çıkarın 0
1
pool
, o zamandan bu yana da dahil olmak üzere, maksimum örnek olurdu 9 (0
ve sekiz 4-karakter elemanları ile başlayan 1
1
ve sekiz 4-karakter elemanları ile başlayan 0
).
Bu mantığa göre, o zaman bir şey pool
ilk örnek alarak önce gelen unsurlar gibi ihmal edebiliriz:
pool <- pool[
nchar(pool) > tail(which(n > (2^max_len - rev(2^(0:max_len))[-1] 1)), 1)]
Herkes daha iyi bir yaklaşım olduğunu düşünmüyor musunuz? Bir şey çok daha basit bakan gibi hissediyorum.
EDİT
Niyetimi açıklamak için, kavşaklar ve ipuçları düğümleri olduğu dallar, bir dizi olarak havuz (pool
elemanları) tasvir edeceğim. Aşağıdaki resimde sarı düğüm (yani 010) çizilmiş olduğunu varsayalım. Şimdi, tüm kırmızı "düğümleri 0, 01, 010, havuzundan kaldırılır oluşur.", şube Bu "öneki" zaten zaten o. (bizim örnekte düğüm düğüm yasaklayan örnekleme ile kastedilen budur ^em>önekibizim örnek düğümler).
Eğer örnek düğüm oldu yarı yolda bir dal gibi 01 olarak aşağıdaki şekilde, daha sonra tüm kırmızı düğümleri (0, 01, 010, 011) izin verilmeyen bu yana 0 önekleri 01 ve 01 önekleri hem 010 ve 011.
Örnek olmak istememya1ya0 her junction (yani yürüyen dalları yazı tura at çatal) - ceza hem de örnek olarak: (1) anne (veya büyük anne-babalar, vb.) ya çocuk (Torun, vb.) bu düğüm zaten örnek değil; ve (2) üzerine örnekleme düğüm düğüm orada yeterli büyüklükte istenilen örnek n
elde kalan olacak.
Eğer 010 ilk tercihi ise ikinci rakam yukarıda, siyah düğüm at her düğüm hala (şu anda) geçerli, n <= 4
varsayıyoruz. Örneğin, eğer n==4
ve numune düğüm 1 sonraki (ve bu yüzden bizim tüyo birlikte 01 ve 1), Biz sonradan vermemek düğüm 00 (nedeniyle Kural 2 yukarıda) ama hala almak 000 001 vererek bize 4 elemanlı örnek. Diğer yandan n==5
, eğer düğüm 1 Bu aşamada izin verilmeyen olurdu.
CEVAP
İntro
Bu diğer yanıt gerçekleştirdik dize algoritma sayısal bir çeşididir. Daha hızlıdır ve ya havuz sıralama oluşturma gerektirmez.
Algoritma Anahat
Tamsayı numaraları ikili temsil etmek için kullanabileceğimiz büyük havuzu neslin sorunu ve değerler sıralı eleme kolaylaştıran dizeler. max_len==3
ile örneğin, sayı 1--
-
doldurma gösterir (ondalık) 4
anlamına alabiliriz. Ayrıca, eğer bu numara da alırsak ortadan kaldırılması gereken sayı 4
4 2 ^ x - 1
arasındadır karar veririz. Burada x
sayı dolgu elemanları (2 harf), numaralar ortadan kaldırmak arasında 4
4 2 ^ 2 - 1
(veya arasında 4
ve 7
ifade 100
, 110
ve 111
).
Sorun maç için tam olarak algoritma bazı bölümleri için ayrı olarak ikili potansiyel olarak aynı olacağını numaraları davranıyorsun beri Küçük bir kırışıklık ihtiyacımız var. Örneğin, 100
, 10-
ve 1--
aynı sayıda, ama farklı düzeni içinde tedavi edilmesi gerekir. max_len==3
bir dünyada, 8 Olası numaraları, ama 14 olası bir beyan var:
0 - 000: 0--, 00-
1 - 001:
2 - 010: 01-
3 - 011:
4 - 100: 1--, 10-
5 - 101:
6 - 110: 11-
7 - 111:
0 ve 4 üç olası kodlamalar, 2 ve 6 iki tane var, Ve Tüm Diğerleri sadece bir tane var. Birden çok temsili ile rakamlar için seçimi yüksek olasılık gösteren bir tamsayı havuz kaç numarasını içerir izleme mekanizması oluşturmak istiyoruz. İstediğimiz ağırlıkları belirtmek için sayının sonunda birkaç parça ekleyerek bunu yapabiliriz. Sayımız olur (iki bit burada kullanıyoruz):
jbaum | int | bin | bin.enc | int.enc
0-- | 0 | 000 | 00000 | 0
00- | 0 | 000 | 00001 | 1
000 | 0 | 000 | 00010 | 2
001 | 1 | 001 | 00100 | 3
01- | 2 | 010 | 01000 | 4
010 | 2 | 010 | 01001 | 5
011 | 3 | 011 | 01101 | 6
1-- | 4 | 100 | 10000 | 7
10- | 4 | 100 | 10001 | 8
100 | 4 | 100 | 10010 | 9
101 | 5 | 101 | 10100 | 10
11- | 6 | 110 | 11000 | 11
110 | 6 | 110 | 11001 | 12
111 | 7 | 111 | 11100 | 13
Bir kaç yararlı özellikleri:
enc.bits
kaç kodlama için ihtiyacımız var (bu durumda iki) temsil ederint.enc %% enc.bits
sayı çok açıkça belirtilmiş olduğunu söylerint.enc %/% enc.bits
int
döndürürint * 2 ^ enc.bits explicitly.specified
int.enc
döndürür
explicitly.specified
burada her zaman en az bir rakamla belirtilmiş olduğundan bizim uygulama 0
72 *arasında olduğunu unutmayın. Biz artık tamamen veri yapısını tek tamsayılar kullanarak temsil eden bir kodlama var. Tam sayılar örnek ve istenen sonuçlar, doğru ağırlık, vb üretebilir. Bu yaklaşımın bir sınırlama R 32 bit tamsayı kullandığımız ve max_len==25
kadar havuzlar için kendimizi sınırlamak çok kodlama için bazı bit rezerve etmeliyiz. Eğer tamsayı çift duyarlıklı kayan nokta ile belirtilen kullandıysanız büyük gidebilirsin, ama yapmadık.
Kaçınarak Yinelenen Alır
Aynı değeri iki kez almak istemiyoruz sağlamak için iki zor yolu vardır
- Değerleri seçmek için kullanılabilir kalır ne iz, ve örnek olanlardan rastgele
- Rastgele tüm olası değerler arasından örnek ve değer önceden seçilmiş olup olmadığını, ve eğer varsa, örnek tekrar kontrol edin
İlk seçenek temiz gibi görünüyor olsa da, aslında çok pahalı bir hesaplama. Ya tarama değerleri seçilmiş bir vektör yapıyor, ya da küçülen bir vektör olmayan diskalifiye değerleri içeren oluşturmak gerektirir. Daralma seçenek yalnızca daha verimli vektör tarama eğer bu vektör yapılan psikiyatrist tarafından referans ile C kodu, ama o zaman bile gerektirir tekrarlanan çeviriler potansiyel olarak büyük bir kısmını vektör ve C. gerektirir
Burada yöntem #2 kullanın. Bu bize rastgele shuffle olası değerler evreni bir kez izin verir, ve daha sonra sırayla her bir değer seçin, diskalifiye oldu, ve eğer varsa kontrol edin, bir tane daha alma vb. Bu değer bizim kodlama olarak seçilmiş olup olmadığını kontrol etmek saçmadır, çünkü çalışır;sıralanmış bir tablo değeri tek başına dayalı bir değerin konumunu çıkarabiliriz. Biz sıralanmış bir tablo kaydı, her değer durumu ve ya Güncelleme ya da doğrudan dizin erişim yoluyla devlet (hayır tarama gerekli) arama.
Örnekler
Temel R Bu algoritma uygulaması olarak kullanılabilira gist. Bu özel uygulama sadece tam çizer çeker. İşte 10 örnek çizer max_len==4
bir havuzu 8 element:
# each column represents a draw from a `max_len==4` pool
set.seed(6); replicate(10, sample0110b(4, 8))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] "1000" "1" "0011" "0010" "100" "0011" "0" "011" "0100" "1011"
[2,] "111" "0000" "1101" "0000" "0110" "0100" "1000" "00" "0101" "1001"
[3,] "0011" "0110" "1001" "0100" "0000" "0101" "1101" "1111" "10" "1100"
[4,] "0100" "0010" "0000" "0101" "1101" "101" "1011" "1101" "0110" "1101"
[5,] "101" "0100" "1100" "1100" "0101" "1001" "1001" "1000" "1111" "1111"
[6,] "110" "0111" "1011" "111" "1011" "110" "1111" "0100" "0011" "000"
[7,] "0101" "0101" "111" "011" "1010" "1000" "1100" "101" "0001" "0101"
[8,] "011" "0001" "01" "1010" "0011" "1110" "1110" "1001" "110" "1000"
Biz de aslında iki uygulamaları o dayanıyordu yöntem #1 için önleme çoğaltır, bir baz R, ve C, ama bile C sürüm değil mi bu kadar hızlı yeni sürüm baz R n
büyük. Bu fonksiyonu eksik çizmek için yeteneği çizer uygulamak, onları burada referans için sunduğumuz bu yüzden:
Karşılaştırmalı testleri
Burada kriterler milisaniye olarak bu/A. Times Q sonucunda ortaya çıkan birkaç işlev karşılaştıran bir set. brodie.b
sürümü bu cevap olarak açıklanmıştır. brodie
orijinal uygulama brodie.C
bazı C. ile aslı, Tüm bu komple örnekleri için gereksinim zorunlu değildir. brodie.str
diğer cevap dizesindeki sürümüdür.
size n jbaum josilber frank tensibai brodie.b brodie brodie.C brodie.str
1 4 10 11 1 3 1 1 1 1 0
2 4 50 - - - 1 - - - 1
3 4 100 - - - 1 - - - 0
4 4 256 - - - 1 - - - 1
5 4 1000 - - - 1 - - - 1
6 8 10 1 290 6 3 2 2 1 1
7 8 50 388 - 8 8 3 4 3 4
8 8 100 2,506 - 13 18 6 7 5 5
9 8 256 - - 22 27 13 14 12 6
10 8 1000 - - - 27 - - - 7
11 16 10 - - 615 688 31 61 19 424
12 16 50 - - 2,123 2,497 28 276 19 1,764
13 16 100 - - 4,202 4,807 30 451 23 3,166
14 16 256 - - 11,822 11,942 40 1,077 43 8,717
15 16 1000 - - 38,132 44,591 83 3,345 130 27,768
Nispeten daha büyük havuzlar için bu ölçekler
system.time(sample0110b(18, 100000))
user system elapsed
8.441 0.079 8.527
Kriter notlar:
- frank ve brodie (brodie eksi.str) karşılaştırmalar (aşağıya bakınız) etkileyecek havuzları, öncesi nesil herhangi bir gerektirmez
- Josilber LP versiyonu
- jbaum OP örneğidir
- tensibai biraz eğer havuz boşsa başarısız yerine çıkmak için değiştirilir
- -python, çok çalıştırmak için değil tamamen tampon için hesap / ile mukayese edilemez
-
ya olanaksız ya da seçenekleri zaman oldukça çok yavaş temsil eder
Zamanlamaları eklemeyin çizim havuzları (0.8
, 2.5
, 401
milisaniye sırasıyla boyutu 4
, 8
ve 16
) için gerekli olan jbaum
, josilber
ve brodie.str
çalışır, ya da sıralama onları (0.1
, 2.7
, 3700
milisaniye için boyutu 4
, 8
ve 16
), çizmek için ek olarak brodie.str
için gerekli olan. Olsun bu eklemek istediğiniz veya belirli bir havuz işlevi çalıştırmak ne kadar bağlıdır. Ayrıca, neredeyse kesinlikle üretme havuzları sıralama daha iyi yolları vardır.
Bu microbenchmark
üç çalışan orta zaman. Kodavailable as a gistgerçi not, *, sample01101
, *sample0110
101 sample01
fonksiyonları önceden yüklemek gerekir.
Nasıl R dizeleri/karakter vektör arada...
Dahil olmadan Ruby modülü üzerinde bir...
hesaplamak ve C boost kullanarak örnek...
5 rasgele bir karakter dizesi oluşturm...
C varsayılan kurucu olmadan yazın örne...