【问题标题】:How to efficiently interpolate data in a Pandas DataFrame row-wise?如何有效地按行插入 Pandas DataFrame 中的数据?
【发布时间】:2019-08-17 01:09:32
【问题描述】:

我有几千个“观察”。每个观察都由位置 (x,y) 和传感器读数 (z) 组成,请参见下面的示例。

我想为 x、y 和 z 数据拟合一个双线性曲面。我目前正在使用来自amroamroamro/gist 的 code-sn-p:

def bi2Dlinter(xdata, ydata, zdata, gridrez):
    X,Y = np.meshgrid(
             np.linspace(min(x), max(x), endpoint=True, num=gridrez),
             np.linspace(min(y), max(y), endpoint=True, num=gridrez))  
    A = np.c_[xdata, ydata, np.ones(len(zdata))]
    C,_,_,_ = scipy.linalg.lstsq(A, zdata)
    Z = C[0]*X + C[1]*Y + C[2]
    return Z

我目前的方法是循环浏览 DataFrame 的行。 (这适用于 1000 次观察,但不适用于更大的数据集。)

ZZ = []
for index, row in df2.iterrows():
    x=row['x1'], row['x2'], row['x3'], row['x4'], row['x5']
    y=row['y1'], row['y2'], row['y3'], row['y4'], row['y5']
    z=row['z1'], row['z2'], row['z3'], row['z4'], row['z5']
    ZZ.append(np.median(bi2Dlinter(x,y,z,gridrez)))
df2['ZZ']=ZZ

如果没有更有效的方法来做到这一点,我会感到惊讶。 有没有办法向量化线性插值?

我输入了代码here,它也会生成虚拟条目。 谢谢

【问题讨论】:

    标签: python python-3.x pandas


    【解决方案1】:

    通常不建议像这样循环数据帧。相反,您应该选择尽可能多地尝试矢量化您的代码。

    首先我们为您的输入创建一个数组

    x_vals = df2[['x1','x2','x3','x4','x5']].values
    y_vals = df2[['y1','y2','y3','y4','y5']].values
    z_vals = df2[['z1','z2','z3','z4','z5']].values
    

    接下来我们需要创建一个处理向量输入的 bi2Dlinter 函数,这涉及更改 linspace/meshgrid 以适用于数组和更改最小二乘函数。通常 scipy.linalg 函数在数组上工作,但据我所知 .lstsq 方法没有。相反,我们可以使用 .SVD 在数组上复制相同的功能。

    def create_ranges(start, stop, N, endpoint=True):
        if endpoint==1:
            divisor = N-1
        else:
            divisor = N
        steps = (1.0/divisor) * (stop - start)
        return steps[:,None]*np.arange(N) + start[:,None]
    
    def linspace_nd(x,y,gridrez):
        a1 = create_ranges(x.min(axis=1), x.max(axis=1), N=gridrez, endpoint=True)
        a2 = create_ranges(y.min(axis=1), y.max(axis=1), N=gridrez, endpoint=True)
        out_shp = a1.shape + (a2.shape[1],)
        Xout = np.broadcast_to(a1[:,None,:], out_shp)
        Yout = np.broadcast_to(a2[:,:,None], out_shp)
        return Xout, Yout
    
    def stacked_lstsq(L, b, rcond=1e-10):
        """
        Solve L x = b, via SVD least squares cutting of small singular values
        L is an array of shape (..., M, N) and b of shape (..., M).
        Returns x of shape (..., N)
        """
        u, s, v = np.linalg.svd(L, full_matrices=False)
        s_max = s.max(axis=-1, keepdims=True)
        s_min = rcond*s_max
        inv_s = np.zeros_like(s)
        inv_s[s >= s_min] = 1/s[s>=s_min]
        x = np.einsum('...ji,...j->...i', v,
                      inv_s * np.einsum('...ji,...j->...i', u, b.conj()))
        return np.conj(x, x)
    
    def vectorized_bi2Dlinter(x_vals, y_vals, z_vals, gridrez):
    
        X,Y = linspace_nd(x_vals, y_vals, gridrez)
        A = np.stack((x_vals,y_vals,np.ones_like(z_vals)), axis=2)
        C = stacked_lstsq(A, z_vals)
        n_bcast = C.shape[0]
        return C.T[0].reshape((n_bcast,1,1))*X + C.T[1].reshape((n_bcast,1,1))*Y + C.T[2].reshape((n_bcast,1,1))
    

    在对 n=10000 行的数据进行测试后,向量化函数的速度明显更快。

    %%timeit
    ZZ = []
    for index, row in df2.iterrows():
        x=row['x1'], row['x2'], row['x3'], row['x4'], row['x5']
        y=row['y1'], row['y2'], row['y3'], row['y4'], row['y5']
        z=row['z1'], row['z2'], row['z3'], row['z4'], row['z5']
        ZZ.append((bi2Dlinter(x,y,z,gridrez)))
    df2['ZZ']=ZZ
    
    Out: 5.52 s ± 17.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    %%timeit
    res = vectorized_bi2Dlinter(x_vals,y_vals,z_vals,gridrez)
    
    Out: 74.6 ms ± 159 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    您应该仔细注意这个向量化函数中发生的事情,并熟悉 numpy 中的广播。我不能将前三个函数归功于我,而是将它们的答案从堆栈溢出中链接起来,以便您理解。

    Vectorized NumPy linspace for multiple start and stop values

    how to solve many overdetermined systems of linear equations using vectorized codes?

    How to use numpy.c_ properly for arrays

    【讨论】:

    • 太棒了!谢谢这个答案让我很开心。我添加了一个显示加速的图表,我一定会深入研究矢量化。
    • 很好,对于更高的订单,您还可以将 numexpr 用于 create_ranges 函数,如附加的 Vectorized NumPy linspace 答案中所示。
    • 哦,哇,你不仅让我开心,你还整理了一个很好的课程:矢量化、广播、numexpr、einsum 等。
    • 我对这个解决方案发布了一个后续问题,因为这两种拟合在增加行数时会产生不同的结果。任何想法,这可能是什么原因造成的?
    • 我只检查了 1000 行数据的结果并且它们匹配。我想我可以单步执行该函数来检查它在哪里发生
    猜你喜欢
    • 2018-07-27
    • 2020-05-14
    • 2021-10-06
    • 2018-11-30
    • 2012-10-05
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多