2017-03-27 11 views
2

以下の特性を持つ確率的ベクトルコレクション(VBA)を作成する必要があります。a)各ベクトルは10次元の配列です。 b)ベクトルのすべてのnull以外の成分は同じ値です。この条件では、コレクションにはすべての可能なベクトルが含まれている必要があります。順列を使って確率的ベクトルをソートする

私はこのようなコレクションにベクトルを一つずつ追加することでこれをやって開始しました:

Dim DB As New Collection: Set DB = New Collection 
'First set: 
    DB.Add Array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0) 
    DB.Add Array(0, 1, 0, 0, 0, 0, 0, 0, 0, 0) 
    DB.Add Array(0, 0, 1, 0, 0, 0, 0, 0, 0, 0) 
    ... 
    DB.Add Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 1) 
'Second set: 
    DB.Add Array(1/2, 1/2, 0, 0, 0, 0, 0, 0, 0, 0) 
    DB.Add Array(1/2, 0, 1/2, 0, 0, 0, 0, 0, 0, 0) 
    DB.Add Array(1/2, 0, 0, 1/2, 0, 0, 0, 0, 0, 0) 
    ... 
    DB.Add Array(0, 0, 0, 0, 0, 0, 0, 0, 1/2, 1/2) 
'Third set: 
    DB.Add Array(1/3, 1/3, 1/3, 0, 0, 0, 0, 0, 0, 0) 
    DB.Add Array(1/3, 1/3, 0, 1/3, 0, 0, 0, 0, 0, 0) 
    ... 

などなど(全体の第十セットを構成する)最後のベクトルを取得するまで:

... 
'Tenth set: 
    DB.Add Array(1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/10) 

あなたが知っているように、コレクションは1023のベクトルになりますので、私の質問は非常にシンプルです(質問は唯一の単純なものだと思います):1023ベクトルを明示的に書くことなくこれを行う方法はありますか? ?

私は、私がこれまでに得たものをお見せしましょう:すべての

まず、私は1の代わりに分数のコンポーネントのと同じ配列を取得することにより、結果を得ることができます。

第2に、最初のセット自体はできません。どのように私は何かを作ることができます

For x = 0 to 9 
    DB.Add Array(x, 0, 0, 0, 0, 0, 0, 0, 0, 0) 
Next x 

結果私はふりをするのですか?私はコードの最後のビットが私にベクトルの最初のセットを与えないことを知っていることに注意してください...それはあなたに私が求めているもののアイデアを与えることです。

第3位では、最初のセットの問題について助けを得たら、他のセットでも同じことができると思います。あなたが10代目までのスクリプトをすべて手伝ってくれることを熱望しているのであれば、私はいいえ、ええと言う人は誰ですか?

私はそれが少しトリッキーなことを知っています!どんな助けも非常に高く評価されます。そして、いつものように、あなたにすべて前もって感謝します。

答えて

2

あなたはこのようなあなたの問題を解決することができます。各配列の組み合わせの数は、Nは10であり、Kは、セットのN番目の数であるN Choose Kによって与えられ、「設定」の

  • 総計で合計10を得ることができます。1 + 10を選択します。2 + 10を選択します。3などを選択して10にします。10を選択します。

  • はその後10個の0と1のバイナリ文字列であることをそれぞれのアレイを検討することができます1023年にループ1と10進数の10桁の2進同等取得 - 1111111111.

    に0000000001からすべての方法をカウントします
  • 2進数を文字列として取得し、その文字列の1を数えます。 1の数字は、数字が属するセットを示します。 3つの1の場合は、配列が3つ目の例になることを意味します。

  • 文字列内の各文字をループし、1つ1つずつ、そのスロットの配列に数えた数の逆数を加えます。例えば。 3つの1の場合、各アレイスロットは1/3になります。それぞれの0に対して、そのスロットに0を加えます。これにより、配列内の項目が確実に1になります。

  • コレクションに配列を追加し、以下のループ

サンプルコード - 私はこの仕事に便利なコードへのリンクのカップルをコメント:

コード:@Robinマッケンジーへ

Option Explicit 

Sub BuildStochasticArray() 

    Dim coll As Collection 
    Dim lngSlots As Long 
    Dim lngCombinations As Long 
    Dim lng1 As Long 
    Dim strBin As String 
    Dim lngNumberOfOnes As Long 
    Dim lng2 As Long 
    Dim var As Variant 
    Dim dblSum As Double 

    Set coll = New Collection 
    ' you have 10 slots 
    lngSlots = 10 
    ' you have this many combinations - 1023 for 10 
    lngCombinations = GetTotalCombinations(lngSlots, lngSlots) 

    For lng1 = 1 To lngCombinations 
     'get binary representation with 0 padding upto lngSlots 
     strBin = DecToBin(lng1, lngSlots) 
     'count number of 1s - this will define you fraction 
     lngNumberOfOnes = Len(strBin) - Len(Replace(strBin, "1", "")) 
     'create the set 
     ReDim var(1 To lngSlots) As Double 
     For lng2 = 1 To lngSlots 
      If Mid$(strBin, lng2, 1) = "1" Then 
       var(lng2) = 1/lngNumberOfOnes 
      Else 
       var(lng2) = 0 
      End If 
     Next lng2 
     'add to collection 
     coll.Add var, strBin 

    Next lng1 

    ' test the procedure by iterating the collection and check each vector adds to 1 
    For lng1 = 1 To lngCombinations 
     var = coll.Item(lng1) 
     ' round to 5 places because of floating point math 
     dblSum = Round(Application.WorksheetFunction.Sum(var), 5) 
     If dblSum <> 1 Then 
      Debug.Print "Error at index " & lng1 
     End If 
    Next lng1 

    Debug.Print "Collection items " & coll.Count 

End Sub 

Function GetTotalCombinations(n As Long, k As Long) As Long 
    Dim i As Long 
    Dim j As Long 
    For i = 1 To k 
     j = j + NChooseK(n, i) 
    Next i 
    GetTotalCombinations = j 
End Function 

' http://www.vb-helper.com/howto_net_calculate_n_choose_k.html 
Function NChooseK(n As Long, k As Long) As Long 
    Dim lngResult As Long 
    Dim i As Long 

    lngResult = 1 
    For i = 1 To k 
     lngResult = lngResult * (n - (k - i)) 
     lngResult = lngResult/i 
    Next i 

    NChooseK = lngResult 

End Function 

' https://stackoverflow.com/questions/22109116/using-dec2bin-with-large-numbers 
Function DecToBin(ByVal lngDec, lngNumberOfBits As Long) As String 
    Dim strBin As String 

    strBin = "" 
    Do While lngDec <> 0 
     strBin = Trim$(Str$(lngDec - 2 * Int(lngDec/2))) & strBin 
     lngDec = Int(lngDec/2) 
    Loop 

    strBin = Right$(String$(lngNumberOfBits, "0") & strBin, lngNumberOfBits) 

    DecToBin = strBin 

End Function 
+0

偉大な答え!私はあなたの戦略を完全に得ました!実際に、私はあなたが投稿するコードが必要ないこともとてもうまくいきました!あなたの答えをありがとう!後で私は問題に私のアプローチを投稿します!もう一度、ありがとうございます:) – Pspl

+0

ありがとう - 0か何かの配列を探しているので、おそらく '(2^N)-1'の合計の組み合わせを取り除くことができます。ここで' N'は数値ですのスロット。 –

+0

はい!私が知っています!配列次元を変数にする必要がある場合は、おそらく便利です。しかし、今のところ、10次元配列の場合にのみ必要です。だからそれは常に1023 ... – Pspl

2

おかげで私はふり配列のコレクションを作成するには、簡単なコードを書く方法を見つけることができました。 @Robinマッケンジーで述べたように

Dim DB As New Collection: Set DB = New Collection 
Dim X01 As Integer, X02 As Integer, X03 As Integer, X04 As Integer, X05 As Integer 
Dim X06 As Integer, X07 As Integer, X08 As Integer, X09 As Integer, X10 As Integer 
Dim CODE As String: Dim SUM As Integer 
For x = 1 To 1023 
    CODE = DecToBin(x) 
    X01 = Val(Mid(Format(CODE, "0000000000"), 1, 1)) 
    X02 = Val(Mid(Format(CODE, "0000000000"), 2, 1)) 
    X03 = Val(Mid(Format(CODE, "0000000000"), 3, 1)) 
    X04 = Val(Mid(Format(CODE, "0000000000"), 4, 1)) 
    X05 = Val(Mid(Format(CODE, "0000000000"), 5, 1)) 
    X06 = Val(Mid(Format(CODE, "0000000000"), 6, 1)) 
    X07 = Val(Mid(Format(CODE, "0000000000"), 7, 1)) 
    X08 = Val(Mid(Format(CODE, "0000000000"), 8, 1)) 
    X09 = Val(Mid(Format(CODE, "0000000000"), 9, 1)) 
    X10 = Val(Mid(Format(CODE, "0000000000"), 10, 1)) 
    SUM = X01 + X02 + X03 + X04 + X05 + X06 + X07 + X08 + X09 + X10 
    DB.Add Array(X01/SUM, X02/SUM, X03/SUM, X04/SUM, X05/SUM, X06/SUM, X07/SUM, X08/SUM, X09/SUM, X10/SUM) 
Next x 

DecToBin機能がDecToBin for larger numbersで提供されています:ここだけの今後の参考のためにそれを行うための私の方法です。

関連する問題