好的,所以这是我的问题。我们正在考虑从公司购买数据集以扩充我们现有的数据集。出于这个问题的目的,让我们说这个数据集对有机数字的位置进行排名(意味着分配给一个地方的数字与分配给另一个地方的数字无关)。技术范围是0到无穷大,但从我看到的样本集,它是0到70.根据样本,它绝对不是一个统一的分布(10,000个中可能有5个位置得分超过40, 50得分超过10,1000得分超过1)。在我们决定购买此套装之前,我们希望对其进行模拟,以便我们了解它的实用性。
所以,为了模拟它,我一直在考虑为每个地方生成一个随机数(大约150,000个随机数)。但是,我还想保持数据的精神,并保持分布相对相同(或至少合理地接近)。我一整天都在绞尽脑汁想着想办法做到这一点,而且空洞。
我想到的是将随机数平方(在0和sqrt(70)之间)。但这有利于少于1和更大的数字。
我认为他的真正分布在第一象限应该是双曲线的...我只是在说明如何将随机数的线性均匀分布变成双曲线分布(如果双曲线甚至是我想要的话)首先)。
有什么想法吗?
所以,总而言之,这是我想要的分布(大约):
答案 0 :(得分:10)
查看可靠性分析中使用的分布 - 它们往往具有这些长尾巴。相对简单的可能性是具有P(X> x)= exp [ - (x / b)^ a]的Weibull分布。
将您的值拟合为P(X> 1)= 0.1且P(X> 10)= 0.005,得到a = 0.36且b = 0.1。这意味着P(X> 40)* 10000 = 1.6,这有点太低,但P(X> 70)* 10000 = 0.2这是合理的。
修改强> 哦,并且从均匀(0,1)值U生成Weibull分布的随机变量,只需计算b * [ - log(1-u)] ^(1 / a)。在我错误计算的情况下,这是1-P(X> x)的反函数。
答案 1 :(得分:8)
几年前写的PHP4,只需选择你的发行版:
<?php
define( 'RandomGaussian', 'gaussian' ) ; // gaussianWeightedRandom()
define( 'RandomBell', 'bell' ) ; // bellWeightedRandom()
define( 'RandomGaussianRising', 'gaussianRising' ) ; // gaussianWeightedRisingRandom()
define( 'RandomGaussianFalling', 'gaussianFalling' ) ; // gaussianWeightedFallingRandom()
define( 'RandomGamma', 'gamma' ) ; // gammaWeightedRandom()
define( 'RandomGammaQaD', 'gammaQaD' ) ; // QaDgammaWeightedRandom()
define( 'RandomLogarithmic10', 'log10' ) ; // logarithmic10WeightedRandom()
define( 'RandomLogarithmic', 'log' ) ; // logarithmicWeightedRandom()
define( 'RandomPoisson', 'poisson' ) ; // poissonWeightedRandom()
define( 'RandomDome', 'dome' ) ; // domeWeightedRandom()
define( 'RandomSaw', 'saw' ) ; // sawWeightedRandom()
define( 'RandomPyramid', 'pyramid' ) ; // pyramidWeightedRandom()
define( 'RandomLinear', 'linear' ) ; // linearWeightedRandom()
define( 'RandomUnweighted', 'non' ) ; // nonWeightedRandom()
function mkseed()
{
srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff) ;
} // function mkseed()
/*
function factorial($in) {
if ($in == 1) {
return $in ;
}
return ($in * factorial($in - 1.0)) ;
} // function factorial()
function factorial($in) {
$out = 1 ;
for ($i = 2; $i <= $in; $i++) {
$out *= $i ;
}
return $out ;
} // function factorial()
*/
function random_0_1()
{
// returns random number using mt_rand() with a flat distribution from 0 to 1 inclusive
//
return (float) mt_rand() / (float) mt_getrandmax() ;
} // random_0_1()
function random_PN()
{
// returns random number using mt_rand() with a flat distribution from -1 to 1 inclusive
//
return (2.0 * random_0_1()) - 1.0 ;
} // function random_PN()
function gauss()
{
static $useExists = false ;
static $useValue ;
if ($useExists) {
// Use value from a previous call to this function
//
$useExists = false ;
return $useValue ;
} else {
// Polar form of the Box-Muller transformation
//
$w = 2.0 ;
while (($w >= 1.0) || ($w == 0.0)) {
$x = random_PN() ;
$y = random_PN() ;
$w = ($x * $x) + ($y * $y) ;
}
$w = sqrt((-2.0 * log($w)) / $w) ;
// Set value for next call to this function
//
$useValue = $y * $w ;
$useExists = true ;
return $x * $w ;
}
} // function gauss()
function gauss_ms( $mean,
$stddev )
{
// Adjust our gaussian random to fit the mean and standard deviation
// The division by 4 is an arbitrary value to help fit the distribution
// within our required range, and gives a best fit for $stddev = 1.0
//
return gauss() * ($stddev/4) + $mean;
} // function gauss_ms()
function gaussianWeightedRandom( $LowValue,
$maxRand,
$mean=0.0,
$stddev=2.0 )
{
// Adjust a gaussian random value to fit within our specified range
// by 'trimming' the extreme values as the distribution curve
// approaches +/- infinity
$rand_val = $LowValue + $maxRand ;
while (($rand_val < $LowValue) || ($rand_val >= ($LowValue + $maxRand))) {
$rand_val = floor(gauss_ms($mean,$stddev) * $maxRand) + $LowValue ;
$rand_val = ($rand_val + $maxRand) / 2 ;
}
return $rand_val ;
} // function gaussianWeightedRandom()
function bellWeightedRandom( $LowValue,
$maxRand )
{
return gaussianWeightedRandom( $LowValue, $maxRand, 0.0, 1.0 ) ;
} // function bellWeightedRandom()
function gaussianWeightedRisingRandom( $LowValue,
$maxRand )
{
// Adjust a gaussian random value to fit within our specified range
// by 'trimming' the extreme values as the distribution curve
// approaches +/- infinity
// The division by 4 is an arbitrary value to help fit the distribution
// within our required range
$rand_val = $LowValue + $maxRand ;
while (($rand_val < $LowValue) || ($rand_val >= ($LowValue + $maxRand))) {
$rand_val = $maxRand - round((abs(gauss()) / 4) * $maxRand) + $LowValue ;
}
return $rand_val ;
} // function gaussianWeightedRisingRandom()
function gaussianWeightedFallingRandom( $LowValue,
$maxRand )
{
// Adjust a gaussian random value to fit within our specified range
// by 'trimming' the extreme values as the distribution curve
// approaches +/- infinity
// The division by 4 is an arbitrary value to help fit the distribution
// within our required range
$rand_val = $LowValue + $maxRand ;
while (($rand_val < $LowValue) || ($rand_val >= ($LowValue + $maxRand))) {
$rand_val = floor((abs(gauss()) / 4) * $maxRand) + $LowValue ;
}
return $rand_val ;
} // function gaussianWeightedFallingRandom()
function logarithmic($mean=1.0, $lambda=5.0)
{
return ($mean * -log(random_0_1())) / $lambda ;
} // function logarithmic()
function logarithmicWeightedRandom( $LowValue,
$maxRand )
{
do {
$rand_val = logarithmic() ;
} while ($rand_val > 1) ;
return floor($rand_val * $maxRand) + $LowValue ;
} // function logarithmicWeightedRandom()
function logarithmic10( $lambda=0.5 )
{
return abs(-log10(random_0_1()) / $lambda) ;
} // function logarithmic10()
function logarithmic10WeightedRandom( $LowValue,
$maxRand )
{
do {
$rand_val = logarithmic10() ;
} while ($rand_val > 1) ;
return floor($rand_val * $maxRand) + $LowValue ;
} // function logarithmic10WeightedRandom()
function gamma( $lambda=3.0 )
{
$wLambda = $lambda + 1.0 ;
if ($lambda <= 8.0) {
// Use direct method, adding waiting times
$x = 1.0 ;
for ($j = 1; $j <= $wLambda; $j++) {
$x *= random_0_1() ;
}
$x = -log($x) ;
} else {
// Use rejection method
do {
do {
// Generate the tangent of a random angle, the equivalent of
// $y = tan(pi * random_0_1())
do {
$v1 = random_0_1() ;
$v2 = random_PN() ;
} while (($v1 * $v1 + $v2 * $v2) > 1.0) ;
$y = $v2 / $v1 ;
$s = sqrt(2.0 * $lambda + 1.0) ;
$x = $s * $y + $lambda ;
// Reject in the region of zero probability
} while ($x <= 0.0) ;
// Ratio of probability function to comparison function
$e = (1.0 + $y * $y) * exp($lambda * log($x / $lambda) - $s * $y) ;
// Reject on the basis of a second uniform deviate
} while (random_0_1() > $e) ;
}
return $x ;
} // function gamma()
function gammaWeightedRandom( $LowValue,
$maxRand )
{
do {
$rand_val = gamma() / 12 ;
} while ($rand_val > 1) ;
return floor($rand_val * $maxRand) + $LowValue ;
} // function gammaWeightedRandom()
function QaDgammaWeightedRandom( $LowValue,
$maxRand )
{
return round((asin(random_0_1()) + (asin(random_0_1()))) * $maxRand / pi()) + $LowValue ;
} // function QaDgammaWeightedRandom()
function gammaln($in)
{
$tmp = $in + 4.5 ;
$tmp -= ($in - 0.5) * log($tmp) ;
$ser = 1.000000000190015
+ (76.18009172947146 / $in)
- (86.50532032941677 / ($in + 1.0))
+ (24.01409824083091 / ($in + 2.0))
- (1.231739572450155 / ($in + 3.0))
+ (0.1208650973866179e-2 / ($in + 4.0))
- (0.5395239384953e-5 / ($in + 5.0)) ;
return (log(2.5066282746310005 * $ser) - $tmp) ;
} // function gammaln()
function poisson( $lambda=1.0 )
{
static $oldLambda ;
static $g, $sq, $alxm ;
if ($lambda <= 12.0) {
// Use direct method
if ($lambda <> $oldLambda) {
$oldLambda = $lambda ;
$g = exp(-$lambda) ;
}
$x = -1 ;
$t = 1.0 ;
do {
++$x ;
$t *= random_0_1() ;
} while ($t > $g) ;
} else {
// Use rejection method
if ($lambda <> $oldLambda) {
$oldLambda = $lambda ;
$sq = sqrt(2.0 * $lambda) ;
$alxm = log($lambda) ;
$g = $lambda * $alxm - gammaln($lambda + 1.0) ;
}
do {
do {
// $y is a deviate from a Lorentzian comparison function
$y = tan(pi() * random_0_1()) ;
$x = $sq * $y + $lambda ;
// Reject if close to zero probability
} while ($x < 0.0) ;
$x = floor($x) ;
// Ratio of the desired distribution to the comparison function
// We accept or reject by comparing it to another uniform deviate
// The factor 0.9 is used so that $t never exceeds 1
$t = 0.9 * (1.0 + $y * $y) * exp($x * $alxm - gammaln($x + 1.0) - $g) ;
} while (random_0_1() > $t) ;
}
return $x ;
} // function poisson()
function poissonWeightedRandom( $LowValue,
$maxRand )
{
do {
$rand_val = poisson() / $maxRand ;
} while ($rand_val > 1) ;
return floor($x * $maxRand) + $LowValue ;
} // function poissonWeightedRandom()
function binomial( $lambda=6.0 )
{
}
function domeWeightedRandom( $LowValue,
$maxRand )
{
return floor(sin(random_0_1() * (pi() / 2)) * $maxRand) + $LowValue ;
} // function bellWeightedRandom()
function sawWeightedRandom( $LowValue,
$maxRand )
{
return floor((atan(random_0_1()) + atan(random_0_1())) * $maxRand / (pi()/2)) + $LowValue ;
} // function sawWeightedRandom()
function pyramidWeightedRandom( $LowValue,
$maxRand )
{
return floor((random_0_1() + random_0_1()) / 2 * $maxRand) + $LowValue ;
} // function pyramidWeightedRandom()
function linearWeightedRandom( $LowValue,
$maxRand )
{
return floor(random_0_1() * ($maxRand)) + $LowValue ;
} // function linearWeightedRandom()
function nonWeightedRandom( $LowValue,
$maxRand )
{
return rand($LowValue,$maxRand+$LowValue-1) ;
} // function nonWeightedRandom()
function weightedRandom( $Method,
$LowValue,
$maxRand )
{
switch($Method) {
case RandomGaussian :
$rVal = gaussianWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomBell :
$rVal = bellWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomGaussianRising :
$rVal = gaussianWeightedRisingRandom( $LowValue, $maxRand ) ;
break ;
case RandomGaussianFalling :
$rVal = gaussianWeightedFallingRandom( $LowValue, $maxRand ) ;
break ;
case RandomGamma :
$rVal = gammaWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomGammaQaD :
$rVal = QaDgammaWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomLogarithmic10 :
$rVal = logarithmic10WeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomLogarithmic :
$rVal = logarithmicWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomPoisson :
$rVal = poissonWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomDome :
$rVal = domeWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomSaw :
$rVal = sawWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomPyramid :
$rVal = pyramidWeightedRandom( $LowValue, $maxRand ) ;
break ;
case RandomLinear :
$rVal = linearWeightedRandom( $LowValue, $maxRand ) ;
break ;
default :
$rVal = nonWeightedRandom( $LowValue, $maxRand ) ;
break ;
}
return $rVal;
}
?>
答案 2 :(得分:2)
生成遵循给定分布的随机数的最简单(但不是非常有效)的方法是称为Von Neumann Rejection的技术。
这项技术的简单探索就是这样。创建一个完全包含您的发行版的框。 (让我们调用您的发布内容f
)然后在框中选择一个随机点(x,y)
。如果是y < f(x)
,则使用x
作为随机数。如果y > f(x)
,则放弃x
和y
并选择另一个点。继续,直到您有足够的值来使用。您拒绝的x
值将根据f
分发。
答案 3 :(得分:0)
这种天真的做法很可能会以某种我现在看不到的方式扭曲分布。这个想法只是迭代你的第一个数据集,排序和成对。然后在每对之间随机化15个新数字以获得新数组。
Ruby示例,因为我不太讲PHP。希望这么简单的想法应该很容易转换成PHP。
numbers=[0.1,0.1,0.12,0.13,0.15,0.17,0.3,0.4,0.42,0.6,1,3,5,7,13,19,27,42,69]
more_numbers=[]
numbers.each_cons(2) { |a,b| 15.times { more_numbers << a+rand()*(b-a) } }
more_numbers.sort!