2017-11-17 42 views
0

C#에서 다항식 분포에서 샘플링하는 간단한 방법을 구현하고자했습니다. 첫 번째 인수는 샘플링하려는 정수의 배열이고 두 번째 인수는 각 정수를 선택할 확률입니다.C#에서 다항식을 샘플링하는 간단한 방법은 무엇이 잘못 되었나요?

파이썬에서 numpy를 사용하면 결과가 의미가 있습니다.

np.random.choice(np.array([1,2,3,4,5,6]),p=np.array([.624,.23,.08,.04, .02, .006]),size=len(b)) 

나는 1의 (확률 62 %)를 많이, 2의의 무리, 나는 C#을 (에서 아래의 구현을 시도 할 때 일부 세의 등

그러나, 매우 간단 역은 다항에 대한 샘플링 변환을 얻을 , 유일한 무작위 변수에 의존), 나는 정말 이상한 결과가납니다. 1000 개의 모든 샘플에 대해, 나는 모든 1을 종종 찾습니다. 때로는 모든 3을 찾을 수 있습니다 (!! ??). 결과는 결코 당신이 기대하는 것과 같이 보이지 않습니다 (그리고 파이썬 함수에서 얻은 것 - 몇 번 실행 해보십시오). 이러한 프리미티브에 의존하기 때문에 이것은 무서운 것입니다. 누구든지 C# 버전의 문제점을 파악할 수 있습니까?

static void Main(string[] args) 
    { 
     int[] iis = new int[7]; 
     int[] itms = new int[] { 1, 2, 3, 4, 5, 6 }; 
     double[] probs = new double[] { .624, .23, .08, .04, .02, .006 }; 
     for (int i = 0; i < 1000; i++) 
     { 
      iis[MultinomialSample(itms, probs)] += 1; 
     } 

     foreach (var ii in iis) 
     { 
      Console.Write(ii + ","); 
     } 

     Console.Read(); 
    } 


    private static int MultinomialSample(int[] s, double[] ps) 
    { 
     double[] cumProbs = new double[ps.Length]; 
     cumProbs[0] = ps[0]; 

     for (int i = 1; i < ps.Length; i++) 
     { 
      cumProbs[i] = cumProbs[i - 1] + ps[i]; 
     } 

     Random random = new Random(); 
     double u = random.NextDouble(); 

     for (int i = 0; i < cumProbs.Length - 1; i++) 
     { 
      if (u < cumProbs[i]) 
      { 
       return s[i]; 
      } 
     } 

     return s[s.Length - 1]; 
    } 
+2

당신은'당신이 MultinomialSample''호출 할 때마다 Random'를 초기화하고 . 이러한 호출이 매우 가깝다면 'Random'은 동일한 시드 (시스템 클록을 기반으로)로 초기화됩니다. private 클래스 필드를'Random'으로 만드십시오 :'private static Random random = new Random();'또는'Main'의 인자로 메소드에 넘겨 주면, 한번만 초기화됩니다. –

답변

1

당신은 Random 당신이 MultinomialSample를 호출 할 때마다 초기화하고 있습니다. 이러한 호출이 매우 근접한 경우 Random은 동일한 시드 (시스템 클럭 기준)로 초기화됩니다. private static Random random = new Random();를하거나 한 번만 초기화 될 Main에서 인수로 방법으로 전달할 : 만들기 Random 개인 클래스 필드 중 하나를 시도

private static Random random = new Random(); 

private static int MultinomialSample(IReadOnlyList<int> sample, 
    IReadOnlyList<double> probabilities) 
{ 
    var cumProbs = new double[probabilities.Count]; 
    cumProbs[0] = probabilities[0]; 

    for (var i = 1; i < probabilities.Count; i++) 
    { 
     cumProbs[i] = cumProbs[i - 1] + probabilities[i]; 
    } 

    for (var i = 0; i < cumProbs.Length - 1; i++) 
    { 
     if (random.NextDouble() < cumProbs[i]) 
     { 
      return sample[i]; 
     } 
    } 

    return sample[sample.Count - 1]; 
} 

private static void Main() 
{ 
    var iis = new int[7]; 
    var items = new[] {1, 2, 3, 4, 5, 6}; 
    var probabilities = new[] {.624, .23, .08, .04, .02, .006}; 

    for (int i = 0; i < 1000; i++) 
    { 
     iis[MultinomialSample(items, probabilities)] ++; 
    } 

    Console.WriteLine(string.Join(", ", iis)); 

    Console.WriteLine("\nDone!\nPress any key to exit..."); 
    Console.ReadKey(); 
}