我可以使用numpy函数[0,2*pi)
在np.arange()
上获得一个统一的网格,但是,我想要一个点数相同但在一定间隔内点密度更高的网格,即具有例如, [pi,1.5*pi]
上的网格更细。如何实现这一点,是否有一个接受密度函数的numpy函数,其输出是具有该密度的网格?
答案 0 :(得分:3)
对于在Stack Overflow上找不到类似的问答,我感到很惊讶。对于random numbers from a discrete distribution,有一些方法可以做类似的事情,但不能用于连续分布,也不能作为修改后的np.arange
或np.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,而不要使用任何更高阶。