6

現実的なキー押下イベントをシミュレートしようとしています。そのため、SendInput() メソッドを使用していますが、より大きな結果を得るには、keyDOWN イベントと KeyUP イベントの間の遅延を指定する必要があります。以下の数値は、DOWN イベントと UP イベントの間の経過時間をミリ秒単位で示しています (これらは実際/有効です)。

96 95 112 111 119 104 143 96 95 104 120 112 111 88 104 119 111 103 95 104 95 127 112 143 144 143 128 144 112 111 111 111 111 111 111 111 111 111 111 111 111 111 111 135 118 147 96 135 103 64 64 64 87 112 88 111 111 112 111 104 87 95

出力を簡略化できます。

遅延 64 ~ 88 ミリ秒 -> 時間の 20%

遅延 89 ~ 135 ミリ秒 -> 時間の 60%

遅延 136 - 150 ミリ秒 -> 時間の 20 %

上記の確率に従ってイベントをトリガーするにはどうすればよいですか? ここに私が今使っているコードがあります:

        private void button2_Click(object sender, EventArgs e)
        {
            textBox2.Focus();
            Random r = new Random();
            int rez = r.Next(0, 5); // 0,1,2,3,4 - five numbers total

            if (rez == 0) // if 20% (1/5)
            {
                Random r2 = new Random();
                textBox2.AppendText(" " + rez + " " + r2.Next(64, 88) + Environment.NewLine);
// do stuff
            }
            else if (rez == 4)//if 20% (1/5)
            {
                Random r3 = new Random();
                textBox2.AppendText(" " + rez + " " + r3.Next(89, 135) + Environment.NewLine);
// do stuff

            }
            else // if 1 or 2 or 3 (3/5) -> 60%
            {
                Random r4 = new Random();
                textBox2.AppendText(" " + rez + " " + r4.Next(136, 150) + Environment.NewLine);
// do stuff

            }

        }

このコードには大きな問題があります。理論的には、数百万回の反復の後、結果のグラフは次のようになります。

比較

この問題に対処するには?

編集:解決策は、人々が提案したように配布を使用することでした。

そのようなコードのJava実装は次のとおりです。

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#nextGaussian%28%29

C# の実装は次のとおりです。

整数範囲から正規分布ランダムを生成する方法は?

「偏差」の値を少し減らすことをお勧めしますが。

ここに興味深いmsdnの記事があります

http://blogs.msdn.com/b/ericlippert/archive/2012/02/21/generating-random-non-uniform-data-in-c.aspx

みんな助けてくれてありがとう!

4

3 に答える 3

2

これは正しい考えです。確率空間を 0 と 1 の間で分割できるように、int ではなく double を使用する必要があると思います。これにより、次のように、より細かい粒度を得ることができます。

  1. すべての値を最大値で割って、実際の値を正規化します
  2. 値をバケットに分割します - バケットが多いほど、グラフは連続ケースに近くなります
  3. 現在、バケットが大きいほど、イベントが発生する可能性が高くなります。したがって、各バケットに含まれる要素の数に応じて間隔 [0,1] を分割します。したがって、20 個の実際の値があり、バケットに 5 個の値がある場合、間隔の 4 分の 1 を占めます。
  4. 各テストで、Random.NextDouble() を使用して 0 ~ 1 の乱数を生成し、乱数が該当するバケットに該当するパラメータでイベントを発生させます。したがって、指定した数値については、5 バケットの値は次のとおりです。

ここに画像の説明を入力

これはコード例に入れるには少し多すぎますが、これが正しい考えを与えることを願っています

于 2012-04-30T10:46:13.633 に答える
2

正規分布を生成する必要があるようです。組み込みの .NET クラスは、Uniform Distributionを生成します。

Box-Muller transformを使用することにより、組み込みの Random クラスを使用して、ガウス分布または正規分布の乱数が可能です。

このような素敵な確率曲線になるはずです

正規分布

( http://en.wikipedia.org/wiki/Normal_distributionから取得)

正規分布乱数を整数範囲に変換するには、ボックス ミュラー変換がこれにも役立ちます。プロセスと数学的証明へのリンクを説明するこの前の質問と回答を参照してください。

于 2012-04-30T10:52:19.433 に答える
1

可能なアプローチの 1 つは、遅延をExponential Distributionとしてモデル化することです。指数分布は、一定の平均レートで継続的かつ独立して発生するイベント間の時間をモデル化します。これは、問題を考えると公正な仮定のように聞こえます。

実際に観測された遅延の平均の逆数をとることでパラメーター ラムダを推定し、このアプローチを使用して分布をシミュレートできます。

遅延 = -Math.Log(random.NextDouble()) / ラムダ

ただし、サンプルを見ると、データは平均値の周りに「集中」しすぎて純粋な指数ではないように見えるため、そのようにシミュレートすると、適切な平均値で遅延が発生しますが、広がりすぎてサンプルと一致しません。

これに対処する 1 つの方法は、プロセスをシフトされた Exponential としてモデル化することです。基本的に、プロセスは、指数の 0 ではなく、値が取ることができる最小値を表す値によってシフトされます。コードでは、サンプルから観測された最小値としてシフトを取得すると、次のようになります。

var sample = new List<double>()
                  {
                     96,
                     95,
                     112,
                     111,
                     119,
                     104,
                     143,
                     96,
                     95,
                     104,
                     120,
                     112
                  };

var min = sample.Min();
sample = sample.Select(it => it - min).ToList();

var lambda = 1d / sample.Average();

var random = new Random();
var result = new List<double>();
for (var i = 0; i < 100; i++)
{
   var simulated = min - Math.Log(random.NextDouble()) / lambda;
   result.Add(simulated);
   Console.WriteLine(simulated);
}

本質的にエイダンのアプローチに似ている簡単な代替手段は、再サンプリングすることです。元のサンプルからランダムな要素を選択すると、結果は正確に目的の分布になります。

var sample = new List<double>()
                  {
                     96,
                     95,
                     112,
                     111,
                     119,
                     104,
                     143,
                     96,
                     95,
                     104,
                     120,
                     112
                  };

var random = new Random();
var size = sample.Count();
for (var i = 0; i < 100; i++)
{
   Console.WriteLine(sample[random.Next(0, size)]);
}
于 2012-05-02T03:48:40.010 に答える