如何在Python中生成对数均匀分布?

20

在Python中,我找不到一个内置的函数来生成一个对数均匀分布,给定一个最小值和最大值(R语言的等效函数在这里),类似于: loguni[n, exp(min), exp(max), base],返回范围在exp(min)和exp(max)之间的n个对数均匀分布。

然而最接近的是numpy.random.uniform函数。


你的链接无法使用。除此之外,请查看scipy.stats(numpy仅提供常见的分布)。如果scipy没有提供它,请自己实现,可以基于你的R等价物或者采用接受-拒绝算法,这通常很容易(但不一定是最快的)。 - sascha
谢谢指出这个问题!已更改链接,现在应该可以使用了。 - jkrish
你可以将均匀分布进行指数化。 - Arya McCarthy
@aryamccarthy 使用numpy.random.uniform [https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.uniform.html]?没错!谢谢! - jkrish
1
你真的需要查看Markdown链接语法。方括号被解释为链接的一部分。 - Arya McCarthy
7个回答

26

来自http://ecolego.facilia.se/ecolego/show/Log-Uniform%20Distribution

在对数均匀分布中,假设对数转换后的随机变量是均匀分布的。

因此

logU(a, b) ~ exp(U(log(a), log(b))

因此,我们可以使用numpy创建对数均匀分布:

def loguniform(low=0, high=1, size=None):
    return np.exp(np.random.uniform(low, high, size))

如果您想选择不同的基数,我们可以定义一个新函数如下:

def lognuniform(low=0, high=1, size=None, base=np.e):
    return np.power(base, np.random.uniform(low, high, size))

编辑: @joaoFaria的回答也是正确的。

def loguniform(low=0, high=1, size=None):
    return scipy.stats.reciprocal(np.exp(low), np.exp(high)).rvs(size)

这很危险。当绘制0.0时,它会产生一个“RuntimeWarning”,表示你正在除以零。 - Arya McCarthy
@aryamccarthy 确实!但是我的分布将具有> 0.0的值,因此我可以将其处理为异常情况。 - jkrish
1
我建议@Scott使用不同的默认值。我执行了他的代码,反复出现“OverflowError:Range exceeds bounds.” - Arya McCarthy
@ScottGigante 谢谢!我担心对于 high = np.exp(1000) 我会遇到类似的错误:RuntimeWarning: overflow encountered in exp; OverflowError: Range exceeds valid bounds. - jkrish
2
@Anatoly-Alekseev 这真的应该是一个单独的问题。但是如果你需要提示,你链接页面底部有所需代码的绝佳示例。您只需将pdf替换为对数均匀分布的pdf:$$f_{X}(x) = \frac{I_{[e^a, e^b]}(x)}{x(b - a)}$$. 推导在这里: https://stats.stackexchange.com/questions/110070/log-uniform-distributions - Scott Gigante
显示剩余5条评论

18

SciPy v1.4包含一个loguniform随机变量:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.loguniform.html

以下是使用它的方法:

from scipy.stats import loguniform

rvs = loguniform.rvs(1e-2, 1e0, size=1000)

这将创建均匀分布在0.01和1之间的随机变量。最好通过可视化对数标度的直方图来展示:

这种“对数标度”适用于任何底数; loguniform.rvs(2**-2, 2**0, size=1000)也会产生对数均匀分布的随机变量。更多细节请参阅loguniform的文档。


8

我相信 scipy.stats.reciprocal 是您想要的分布。
根据文档:

The probability density function for reciprocal is:

f(x, a, b) = \frac{1}{x \log(b/a)}

for a <= x <= b and a, b > 0

reciprocal takes a and b as shape parameters.


快点,这看起来不像是对数均匀分布,更像是一个反对数。如果我错了,请纠正我。 - Guillaume Chevalier
@GuillaumeChevalier同意,这不是一个对数均匀分布。 - Jinglesting
这个概率密度函数与@ScottGigante回答中提到的此链接中的有何不同? - joaoFaria
1
这是正确的答案:倒数分布的对数是均匀分布! - Arkandias
这是正确的答案。通过实验验证:import numpy as np; import matplotlib.pyplot as plt; import scipy.stats; plt.hist(loguniform(0, np.log(20), 20000), bins=50); plt.hist(scipy.stats.reciprocal(1, 20).rvs(20000), bins=50) - Scott Gigante

0
from random import random
from math import log

def loguniform(lo,hi,seed=random()):
    return lo ** ((((log(hi) / log(lo)) - 1) * seed) + 1)

您可以使用特定的种子值进行检查:lognorm(10,1000,0.5) 返回 100.0

0
更好的方法是,不要直接从对数均匀分布中生成样本,而是应该创建对数均匀分布密度。
在统计学中,这是一个倒数分布,它已经在SciPy中实现了:scipy.stats.reciprocal。例如,要构建一个符合10^{x~U[-1,1]}的样本,可以执行以下操作:
rv = scipy.stats.reciprocal(a=0.1,b=10)
x = rv.rvs(N)

或者,我编写并使用以下代码来对任何类似于scipy.stats的(冻结的)随机变量进行对数转换

class LogTransformRV(scipy.stats.rv_continuous):
    def __init__(self,rv,base=10):
        self.rv = rv
        self.base = np.e if base in {'e','E'} else base
        super(LogTransformRV, self).__init__()
        self.a,self.b = self.base ** self.rv.ppf([0,1])

    def _pdf(self,x):
        return self.rv.pdf(self._log(x))/(x*np.log(self.base)) # Chain rule

    def _cdf(self,x):
        return self.rv.cdf(self._log(x)) 

    def _ppf(self,y):
        return self.base ** self.rv.ppf(y)

    def _log(self,x):
        return np.log(x)/np.log(self.base)

0

这里有一个:

只需使用提供的.rvs()方法即可:

class LogUniform(HyperparameterDistribution):
    """Get a LogUniform distribution.
    For example, this is good for neural networks' learning rates: that vary exponentially."""

    def __init__(self, min_included: float, max_included: float):
        """
        Create a quantized random log uniform distribution.
        A random float between the two values inclusively will be returned.
        :param min_included: minimum integer, should be somehow included.
        :param max_included: maximum integer, should be somehow included.
        """
        self.log2_min_included = math.log2(min_included)
        self.log2_max_included = math.log2(max_included)
        super(LogUniform, self).__init__()

    def rvs(self) -> float:
        """
        Will return a float value in the specified range as specified at creation.
        :return: a float.
        """
        return 2 ** random.uniform(self.log2_min_included, self.log2_max_included)

    def narrow_space_from_best_guess(self, best_guess, kept_space_ratio: float = 0.5) -> HyperparameterDistribution:
        """
        Will narrow, in log space, the distribution towards the new best_guess.
        :param best_guess: the value towards which we want to narrow down the space. Should be between 0.0 and 1.0.
        :param kept_space_ratio: what proportion of the space is kept. Default is to keep half the space (0.5).
        :return: a new HyperparameterDistribution that has been narrowed down.
        """
        log2_best_guess = math.log2(best_guess)
        lost_space_ratio = 1.0 - kept_space_ratio
        new_min_included = self.log2_min_included * kept_space_ratio + log2_best_guess * lost_space_ratio
        new_max_included = self.log2_max_included * kept_space_ratio + log2_best_guess * lost_space_ratio
        if new_max_included <= new_min_included or kept_space_ratio == 0.0:
            return FixedHyperparameter(best_guess).was_narrowed_from(kept_space_ratio, self)
        return LogUniform(2 ** new_min_included, 2 ** new_max_included).was_narrowed_from(kept_space_ratio, self)

如果您对原始项目中的LogNormal分布也感兴趣,那么它也包含在内。

来源:

许可证:

  • Apache License 2.0,版权所有2019年Neuraxio Inc.

0
from neuraxle.hyperparams.distributions import LogUniform

# Create a Log Uniform Distribution that ranges from 0.001 to 0.1: 
learning_rate_distribution = LogUniform(0.001, 0.1)

# Get a Random Value Sample (RVS) from the distribution: 
learning_rate_sample = learning_rate_distribution.rvs()

print(learning_rate_sample)

示例输出:

0.004532

这是使用 Neuraxle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接