具有非均匀间隔的np.arange或np.linspace的替代

时间:2020-07-04 21:45:22

标签: python numpy scipy

我可以使用numpy函数[0,2*pi)np.arange()上获得一个统一的网格,但是,我想要一个点数相同但在一定间隔内点密度更高的网格,即具有例如, [pi,1.5*pi]上的网格更细。如何实现这一点,是否有一个接受密度函数的numpy函数,其输出是具有该密度的网格?

1 个答案:

答案 0 :(得分:3)

对于在Stack Overflow上找不到类似的问答,我感到很惊讶。对于random numbers from a discrete distribution,有一些方法可以做类似的事情,但不能用于连续分布,也不能作为修改后的np.arangenp.linspace

如果您需要获得x范围的绘图,并且在您希望函数波动更快的区域中进行更精细的采样,则可以创建一个非线性函数,该函数接受输入范围为0到1并在相同范围内产生输出非线性进行的范围。例如:

def f(x):
    return x**2

angles = 2*np.pi*f(np.linspace(0, 1, num, endpoint=False))

这将在零附近产生精细采样,在2 * pi附近产生粗糙采样。 要更精细地控制采样密度,可以使用以下功能。另外,它还允许随机抽样。

import numpy as np

def density_space(xs, ps, n, endpoint=False, order=1, random=False):
    """Draw samples with spacing specified by a density function.

    Copyright Han-Kwang Nienhuys (2020).
    License: any of: CC-BY, CC-BY-SA, BSD, LGPL, GPL.
    Reference: https://stackoverflow.com/a/62740029/6228891
    
    Parameters:
        
    - xs: array, ordered by increasing values.
    - ps: array, corresponding densities (not normalized).
    - n: number of output values.
    - endpoint: whether to include x[-1] in the output.
    - order: interpolation order (1 or 2). Order 2 will
      require dense sampling and a smoothly varying density 
      to work correctly.
    - random: whether to return random samples, ignoring endpoint).
      in this case, n can be a shape tuple.

    Return:
        
    - array, shape (n,), with values from xs[0] to xs[-1]
    """
    from scipy.interpolate import interp1d
    from scipy.integrate import cumtrapz
    
    cps = cumtrapz(ps, xs, initial=0)
    cps *= (1/cps[-1])
    intfunc = interp1d(cps, xs, kind=order)
    if random:
        return intfunc(np.random.uniform(size=n))
    else:
        return intfunc(np.linspace(0, 1, n, endpoint=endpoint))

测试:

values = density_space(
    [0, 100, 101, 200],
    [1, 1, 2, 2],
    n=12, endpoint=True)

print(np.around(values))

[  0.  27.  54.  82. 105. 118. 132. 146. 159. 173. 186. 200.]

使用梯形积分创建累积密度函数,梯形积分本质上是基于线性插值的。高阶积分是不安全的,因为输入可能具有(近)间断,例如在示例中从x = 100跳到x = 101。输入的不连续会导致累积密度函数(代码中的{cps)的一阶导数不连续,这将导致平滑插值(2阶或更高)的问题。因此,建议仅对平滑密度函数使用order = 2,而不要使用任何更高阶。