快速平滑分散的数据

时间:2019-10-20 14:06:12

标签: python numpy matplotlib smoothing

我正在寻找一种可以平滑分散数据集的方法。分散的数据集来自对表示栅格的非常大的数组进行采样。我必须对这个数组进行矢量化处理才能对其进行下采样。通过使用matplotlib.pyplot.contour()函数,我得到了一组合理的点值对。

问题在于此信号很嘈杂,我需要对其进行平滑处理。平滑原始数组是不好的,我需要平滑分散的数据。我能找到的最好的函数是下面的函数,该函数是我从Matlab对应函数重写的。虽然此功能可以完成工作,但速度非常慢。我正在寻找替代功能来平滑此数据,或者正在寻找一种使以下功能更快的方法。

def limgrad(self, triangulation, values, dfdx, imax=100):
    """
    See https://github.com/dengwirda/mesh2d/blob/master/hjac-util/limgrad.m
    for original source code.
    """
    # triangulation is a matplotlib.tri.Triangulation instance
    edge = triangulation.edges
    dx = np.subtract(
        triangulation.x[edge[:, 0]], triangulation.x[edge[:, 1]])
    dy = np.subtract(
        triangulation.y[edge[:, 0]], triangulation.y[edge[:, 1]])
    elen = np.sqrt(dx**2+dy**2)
    aset = np.zeros(values.shape)
    ftol = np.min(values) * np.sqrt(np.finfo(float).eps)
    for i in range(1, imax + 1):
        aidx = np.where(aset == i-1)[0]
        if len(aidx) == 0.:
            break
        active_idxs = np.argsort(values[aidx])
        for active_idx in active_idxs:
            adj_edges_idxs = np.where(
                np.any(edge == active_idx, axis=1))[0]
            adjacent_edges = edge[adj_edges_idxs]
            for nod1, nod2 in adjacent_edges:
                if values[nod1] > values[nod2]:
                    fun1 = values[nod2] + elen[active_idx] * dfdx
                    if values[nod1] > fun1+ftol:
                        values[nod1] = fun1
                        aset[nod1] = i
                else:
                    fun2 = values[nod1] + elen[active_idx] * dfdx
                    if values[nod2] > fun2+ftol:
                        values[nod2] = fun2
                        aset[nod2] = i
    return values

1 个答案:

答案 0 :(得分:0)

我找到了自己问题的答案,并在此发布以供参考。上面的算法很慢,因为调用np.where()生成adj_edges_idxs会产生很大的开销。相反,我预先计算了节点邻居,从而消除了开销。它从每秒约80次迭代增加到每秒80,000次。

最终版本如下:

def limgrad(tri, values, dfdx=0.2, imax=100):
    """
    See https://github.com/dengwirda/mesh2d/blob/master/hjac-util/limgrad.m
    for original source code.
    """
    xy = np.vstack([tri.x, tri.y]).T
    edge = tri.edges
    dx = np.subtract(xy[edge[:, 0], 0], xy[edge[:, 1], 0])
    dy = np.subtract(xy[edge[:, 0], 1], xy[edge[:, 1], 1])
    elen = np.sqrt(dx**2+dy**2)
    ffun = values.flatten()
    aset = np.zeros(ffun.shape)
    ftol = np.min(ffun) * np.sqrt(np.finfo(float).eps)
    # precompute neighbor table
    point_neighbors = defaultdict(set)
    for simplex in tri.triangles:
        for i, j in permutations(simplex, 2):
            point_neighbors[i].add(j)
    # iterative smoothing
    for _iter in range(1, imax+1):
        aidx = np.where(aset == _iter-1)[0]
        if len(aidx) == 0.:
            break
        active_idxs = np.argsort(ffun[aidx])
        for active_idx in active_idxs:
            adjacent_edges = point_neighbors[active_idx]
            for adj_edge in adjacent_edges:
                if ffun[adj_edge] > ffun[active_idx]:
                    fun1 = ffun[active_idx] + elen[active_idx] * dfdx
                    if ffun[adj_edge] > fun1+ftol:
                        ffun[adj_edge] = fun1
                        aset[adj_edge] = _iter
                else:
                    fun2 = ffun[adj_edge] + elen[active_idx] * dfdx
                    if ffun[active_idx] > fun2+ftol:
                        ffun[active_idx] = fun2
                        aset[active_idx] = _iter
    flag = _iter < imax
    return ffun, flag