python - 多个 3D 阵列(曲线)的采样/插值

标签 python scipy interpolation pca

我的目标是在 2D 和 3D 空间中按预定义的顺序距离插入曲线,以对多条曲线执行 PCA。

假设一个包含多个 3D 数组(每个数组大小不同)的数据框:

>>> df.curves
0    [[0.0, 0.0, 0.91452991453, 0.91452991453, 1.0]...
1    [[0.0, 0.0, 0.734693877551, 0.734693877551, 1....
2    [[0.0, 0.0, 1.0, 1.0, 1.0], [0.0, 0.6435643564...
3    [[0.0, 0.0, 0.551020408163, 0.551020408163, 1....
4    [[0.0, 0.0, 1.0, 1.0, 1.0], [0.0, 0.4389027431...
5    [[0.0, 0.0, 0.734693877551, 0.734693877551, 1....
Name: curves, dtype: object

>>> df.curves[0]
array([[ 0.        ,  0.        ,  0.73469388,  0.73469388,  1.        ],
       [ 0.        ,  0.1097561 ,  0.47560976,  0.5       ,  1.        ],
       [ 1.        ,  0.65036675,  0.08801956,  0.06845966,  0.        ]])

让我们将维度命名为xyz,其中所有维度的长度都相同,xy 维度单调递增:

3D 绘图

我尝试对数据进行等距采样,并允许具有统一采样率的曲线之间的可比性。

二维曲线的简单采样函数(没有 y dim)将按数据帧行:

def sample2DCurve(row, res=10, method='linear'):    
    # coords of interpolation
    xnew = np.linspace(0, 1, res)

    # call scipy interpolator interp1d
    # create interpolation function for 2D data
    sample2D = interpolate.interp1d(row[0], row[1], kind=method)

    # sample data points based on xnew
    znew = sample2D(xnew)

    return np.array([xnew, znew])

对于 3D 数据,我沿路径使用插值:

def sample3DCurves(row, res=10, method='linear'):
    #npts = row[0].size
    #p = np.zeros(npts, dtype=float)
    #for i in range(1, npts):
    #    dx = row[0][i] - row[0][i-1]
    #    dy = row[1][i] - row[1][i-1]
    #    dz = row[2][i] - row[2][i-1]
    #    v = np.array([dx, dy, dz])
    #    p[i] = p[i-1] + np.linalg.norm(v)
#==============================================================================
    # edit: cleaner algebra
    x, *y, z = row

    # vecs between subsequently measured points
    vecs = np.diff(row)

    # path: cum distance along points (norm from first to ith point)
    path = np.cumsum(np.linalg.norm(vecs, axis=0))
    path = np.insert(path, 0, 0)
#==============================================================================

    ## coords of interpolation
    coords = np.linspace(p[0], p[-1], res) #p[0]=0 p[-1]=max(p)

    # interpolation func for each axis with the path
    sampleX = interpolate.interp1d(p, row[0], kind=method)
    sampleY = interpolate.interp1d(p, row[1], kind=method)
    sampleZ = interpolate.interp1d(p, row[2], kind=method)

    # sample each dim
    xnew = sampleX(coords)
    ynew = sampleY(coords)
    znew = sampleZ(coords)

    return np.array([xnew, ynew, znew])

作为 3D 中的另一种方法,我想沿着等值线在 x,y 平面中形成具有统一半径的圆进行插值:

x,y 平面中 [0,0,0] 附近的圆形等值线,具有 3D 交点

z 值然后根据等值线与投影在 x,y 平面中的(线性)插值曲线的交点进行插值。

但我很难定义圆形线并与 x,y 平面中的曲线/路径向量的投影相交。

非常感谢任何建议! (还有其他语言 - R/Matlab 等)

最佳答案

对于后代,我的粗略(更简单、更 pythonic 代码非常受欢迎)变通解决方案。

如果这实际上是主成分分析研究曲线形状的有用预处理步骤,则仍然是问题/分析。

def seq_sampling(row, res=10, method='linear'):
    #3D sequential along x and y (isocircles):
    x, y, z = row

    #  distance to origin for each point (support vectors lengths)
    point_distance = np.linalg.norm(row[(0,2),], axis=0)

    # isocircle radii
    max_radius = math.sqrt(x[-1]+y[-1])
    radii = np.linspace(0, max_radius, res)

    # last (distance to origin) inner data points per circle (start point of segments)
    start_per_radius = [np.max(np.where(point_distance <= radius)) for radius in radii]

    # initialize coords
    new_x = np.zeros_like(radii)
    new_y = np.zeros_like(radii)
    new_z = np.zeros_like(radii)

    # assign first an last known coordinates
    new_x[0], new_y[0] = x[0], y[0] # 0, 0
    new_x[-1], new_y[-1] = x[-1], y[-1] # 1, 1

    for radius, startpoint in enumerate(start_per_radius[1:-1]):
        # intersect circles of radius with corresponding intersecting vectors
        # based on https://math.stackexchange.com/questions/311921/get-location-of-vector-circle-intersection
        # fix index count (starts with radius > 0)
        radius += 1

        # span line segment with point O outside and point I inside of iso-circle 
        endpoint = startpoint+1

        O_x = x[endpoint]
        O_y = y[endpoint]

        I_x  = x[startpoint]
        I_y  = y[startpoint]

        # coefficients
        a = (O_x-I_x)**2 + (O_y-I_y)**2
        b = 2*((O_x-I_x)*(I_y) + (O_y-I_y)*(I_y))
        c = (I_x)**2 + (I_y)**2 - radii[radius]**2

        # !radicant cannot be zero given:
        # each segment is defined by max point lying inside or on iso-circle and the next point
        # as both axis are monotonically (strict monotonically y) increasing the next point lies outside of the ico-circle
        # thus (in 2D) a segment is intersecting a circle by definition.
        t = 2*c / (- b - math.sqrt(b**2 - 4*a*c))

        #check if intersection lies on line segment / within boundaries of t [0,1]
        if (t >= 0) and (t <= 1):
        new_x[radius], new_y[radius] = (O_x - I_x)*t + I_x, (O_y-I_y)*t + I_y

    # interpolate new_y based on projected new_y 
    new_z = interpolate.interp1d(y, z, kind='linear')(new_y[1:-1])

    # assign first an last known coordinates
    new_z = np.insert(new_z,0,z[0])
    new_z = np.append(new_z,z[-1])

    return  np.array([new_x, new_y, new_z])

3D Plot with circular iso-lines

关于python - 多个 3D 阵列(曲线)的采样/插值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45393603/

相关文章:

Python mysql xampp

python - pandas 中 drop 和 select_dtype 的区别

科学堆栈存储库中的 Python 相对导入与绝对导入

python - 从 csv 文件加载数据并显示在元组列表中

python - 如何在我的ros系统中添加sensor_msgs.msg类型?

python - Excel 的 Beta 分布的 Python 等价物是什么?

python - 使用 Python 求解 4 参数常数(罗德巴德方程)

c++ - 有哪些好的 3D 插值库?

c++ - 双线性插值以放大位图图像

python - 带插值的 vtk 3D 图像旋转/平移 (python)