Python 数据集的高效拼接

Python 数据集的高效拼接,python,optimization,lmfit,Python,Optimization,Lmfit,我有多个测量数据集,我想合并到一个数据集。虽然我有一个有效的解决方案,但它效率非常低,我很乐意得到一些关于如何改进它的建议 将测量值视为一个对象的多个高度贴图,我希望将其合并为一个高度贴图。我的测量不完美,可能有一些倾斜和高度偏移。让我们假设(现在)我们知道x-y位置非常精确。以下是一个例子: import numpy as np import matplotlib.pyplot as plt def height_profile(x, y): radius = 100 ret

我有多个测量数据集,我想合并到一个数据集。虽然我有一个有效的解决方案,但它效率非常低,我很乐意得到一些关于如何改进它的建议

将测量值视为一个对象的多个高度贴图,我希望将其合并为一个高度贴图。我的测量不完美,可能有一些倾斜和高度偏移。让我们假设(现在)我们知道x-y位置非常精确。以下是一个例子:

import numpy as np
import matplotlib.pyplot as plt

def height_profile(x, y):
    radius = 100
    return np.sqrt(radius**2-x**2-y**2)-radius

np.random.seed(123)

datasets = {}

# DATASET 1
x = np.arange(-8, 2.01, 0.1)
y = np.arange(-3, 7.01, 0.1)

xx, yy = np.meshgrid(x, y)
# height is the actual profile + noise
zz = height_profile(xx, yy) + np.random.randn(*xx.shape)*0.001

datasets[1] = [xx, yy, zz]

plt.figure()
plt.pcolormesh(*datasets[1])
plt.colorbar()

# DATASET 2
x = np.arange(-2, 8.01, 0.1)
y = np.arange(-3, 7.01, 0.1)

xx, yy = np.meshgrid(x, y)
# height is the actual profile + noise + random offset + random tilt
zz = height_profile(xx, yy) + np.random.randn(*xx.shape)*0.001 + np.random.rand() + np.random.rand()*xx*0.1 + np.random.rand()*yy*0.1

datasets[2] = [xx, yy, zz]

plt.figure()
plt.pcolormesh(*datasets[2])
plt.colorbar()

# DATASET 3
x = np.arange(-5, 5.01, 0.1)
y = np.arange(-7, 3.01, 0.1)

xx, yy = np.meshgrid(x, y)
# height is the actual profile + noise + random offset + random tilt
zz = height_profile(xx, yy) + np.random.randn(*xx.shape)*0.001 + np.random.rand() + np.random.rand()*xx*0.1 + np.random.rand()*yy*0.1

datasets[3] = [xx, yy, zz]

plt.figure()
plt.pcolormesh(*datasets[3])
plt.colorbar()
要组合这三个(或更多)数据集,我有以下策略:找到数据集之间的重叠,计算重叠区域中数据集之间的总高度差(
剩余重叠
),并尝试使用
lmfit
最小化高度差(剩余)。要在数据集上应用转换(倾斜、偏移等),我有一个专用函数

from lmfit import minimize, Parameters
from copy import deepcopy
from itertools import combinations
from scipy.interpolate import griddata

def data_transformation(dataset, idx, params):
    dataset = deepcopy(dataset)
    
    if 'x_offset_{}'.format(idx) in params:
        x_offset = params['x_offset_{}'.format(idx)].value
    else:
        x_offset = 0

    if 'y_offset_{}'.format(idx) in params:
        y_offset = params['y_offset_{}'.format(idx)].value
    else:
        y_offset = 0
    
    if 'tilt_x_{}'.format(idx) in params:
        x_tilt = params['tilt_x_{}'.format(idx)].value
    else:
        x_tilt = 0

    if 'tilt_y_{}'.format(idx) in params:
        y_tilt = params['tilt_y_{}'.format(idx)].value
    else:
        y_tilt = 0

    if 'piston_{}'.format(idx) in params:
        piston = params['piston_{}'.format(idx)].value
    else:
        piston = 0

    _x = dataset[0] - np.mean(dataset[0])
    _y = dataset[1] - np.mean(dataset[1])

    dataset[0] = dataset[0] + x_offset
    dataset[1] = dataset[1] + y_offset
    dataset[2] = dataset[2] + 2 * (x_tilt * _x + y_tilt * _y) + piston

    return dataset

def residual_overlap(dataset_0, dataset_1):
    xy_0 = np.stack((dataset_0[0].flatten(), dataset_0[1].flatten()), axis=1)
    xy_1 = np.stack((dataset_1[0].flatten(), dataset_1[1].flatten()), axis=1)
    difference = griddata(xy_0, dataset_0[2].flatten(), xy_1) - \
                 dataset_1[2].flatten()

    return difference

def residual(params, datasets):
    datasets = deepcopy(datasets)

    for idx in datasets:
        datasets[idx] = data_transformation(
            datasets[idx], idx, params)

    residuals = []

    for combination in combinations(list(datasets), 2):
        residuals.append(residual_overlap(
            datasets[combination[0]], datasets[combination[1]]))

    residuals = np.concatenate(residuals)
    residuals[np.isnan(residuals)] = 0

    return residuals

def minimize_datasets(params, datasets, **minimizer_kw):
    minimize_fnc = lambda *args, **kwargs: residual(*args, **kwargs)

    datasets = deepcopy(datasets)

    min_result = minimize(minimize_fnc, params,
                          args=(datasets, ), **minimizer_kw)

    return min_result
我像这样进行“缝合”:

params = Parameters()
params.add('tilt_x_2', 0)
params.add('tilt_y_2', 0)
params.add('piston_2', 0)
params.add('tilt_x_3', 0)
params.add('tilt_y_3', 0)
params.add('piston_3', 0)

fit_result = minimize_datasets(params, datasets)

plt.figure()
plt.pcolormesh(*data_transformation(datasets[1], 1, fit_result.params), alpha=0.3, vmin=-0.5, vmax=0)
plt.pcolormesh(*data_transformation(datasets[2], 2, fit_result.params), alpha=0.3, vmin=-0.5, vmax=0)
plt.pcolormesh(*data_transformation(datasets[3], 3, fit_result.params), alpha=0.3, vmin=-0.5, vmax=0)
plt.colorbar()
正如你所看到的,它确实有效,但是我的计算机上这些小数据集的缝合大约需要一分钟。实际上,我有越来越多的数据集

你有没有找到提高缝纫性能的方法


编辑:根据建议,我运行了一个探查器,它显示99.5%的时间花在
griddata
函数上。该函数用于将数据点从数据集_0插值到数据集_1的位置。如果我将方法切换到“最近的”,执行时间将下降到大约一秒钟,但不会发生插值。有机会提高插值速度吗?

浏览一下代码,除了您一遍又一遍地运行
deepcopy()

但是,我建议您进行
评测
。如果您使用的是pycharm,那么可以使用
clock/run
符号进行评测

我相信其他IDE也有这样的功能。通过这种方式,您可以确定哪个函数占用的时间最多

全图:

当我放大到几个函数时(我显示的是谷歌云函数):

你可以看到他们被呼叫了多少次,花了多长时间等等


长话短说,你需要一个剖析器

谢谢你的建议!我会试试这个。我将看看是否可以去掉一些deepcopy。评测已经有助于缩小耗时任务的范围(将数据从一个数据集插入到另一个数据集)。另一个注意事项:PyCharm中的评测功能仅在专业版本中可用。但我可以这样运行配置文件:
import profile;profile.run('minimize_datasets(params,datasets)”,sort='tottime')
@erik,如果这个答案有助于您解决问题,请接受它。在profiler的帮助下,我发现
griddata
是计算中最慢的部分。在每一个优化步骤中,都会进行新的Delaunay三角剖分,这需要大量的时间。解决方案是存储三角剖分,并且在每个优化步骤中只重新进行插值。请参阅此处的更多详细信息: