【问题标题】:Using multiple interpolation functions within a dataframe在数据帧中使用多个插值函数
【发布时间】:2019-04-24 12:14:15
【问题描述】:

我有一个包含许多列的大数据框。为简单起见,假设:

df_sample = pd.DataFrame({'a':np.arange(10)})

我需要在 df_sample 中定义一个新列(比如列'b'),它需要使用一些插值函数,其参数取自列'a'。

现在,问题是每行的插值函数都不同。对于每一行,我从不同的一维网格进行插值;所以我对每一行都有不同的插值函数。所以,我所做的是预先生成这些插值函数并将它们存储到一个数组中。举个例子,下面的代码生成一个样本数组'list_interpfns'

list_interpfns = np.array([None]*10)
for j in range(10):
    list_interpfns[j] = scipy.interpolate.interp1d(np.linspace(0,10*(j+1),10),np.linspace(0,50,10))

要生成 df_sample.b[j],我需要使用带有参数 df_sample.a[j] 的 list_interpfns[j]。由于我无法为此直接应用列公式,因此我将其放入循环中。

df_sample['b'] = 0
for j in range(10):
    df_sample.loc[j,'b'] = list_interpfns[j](df_sample.a[j])

问题是这个操作需要很多时间。在这个小例子中,计算可能看起来很快。但是我的实际程序要大得多,当我比较所有操作所花费的时间时,这个特定的操作顺序占用了总时间的 84%;我需要加快速度。

如果有某种方法可以避免 for 循环(例如使用 df.apply 或其他方法),那么我相信它可以减少操作时间。你能给出可能的替代方案吗?

【问题讨论】:

    标签: python loops interpolation


    【解决方案1】:

    考虑避免多个for 循环和初始化和更新数组和系列的簿记,并使用Series.apply() 将列值传递到函数构建和函数参数:

    def interp_(j):
        return scipy.interpolate.interp1d(np.linspace(0,10*(j+1),10), np.linspace(0,50,10))
    
    df_sample['b_'] = df_sample['a'].apply(lambda x: interp_(x)(x))
    

    结果复制了您的原始结果

    df_sample
    #    a         b        b_
    # 0  0  0.000000  0.000000
    # 1  1  2.500000  2.500000
    # 2  2  3.333333  3.333333
    # 3  3  3.750000  3.750000
    # 4  4  4.000000  4.000000
    # 5  5  4.166667  4.166667
    # 6  6  4.285714  4.285714
    # 7  7  4.375000  4.375000
    # 8  8  4.444444  4.444444
    # 9  9  4.500000  4.500000
    

    即使Series.apply() 仍然是一个循环,时间安排表明处理速度会稍快:

    def run1():
        list_interpfns = np.array([None]*10)
        for j in range(10):
            list_interpfns[j] = scipy.interpolate.interp1d(np.linspace(0,10*(j+1),10),
                                                           np.linspace(0,50,10))            
        df_sample['b'] = 0
        for j in range(10):
            df_sample.loc[j,'b'] = list_interpfns[j](df_sample.a[j])
    
    def run2():
        def interp_(j):
            return scipy.interpolate.interp1d(np.linspace(0,10*(j+1),10), np.linspace(0,50,10))
    
        df_sample['b_'] = df_sample['a'].apply(lambda x: interp_(x)(x))
    
    if __name__=='__main__':
        from timeit import Timer
    
        f1 = Timer("run1()", "from __main__ import run1")
        res1 = f1.repeat(repeat=100, number=1)
        print('LOOP: {}'.format(np.mean(res1)))
    
        f2 = Timer("run2()", "from __main__ import run2")
        res2 = f2.repeat(repeat=100, number=1)
        print('APPLY: {}'.format(np.mean(res2)))
    
    # LOOP: 0.006322918700000002
    # APPLY: 0.0015046094699999867
    

    【讨论】:

    • 感谢您的回复。不幸的是,我的实际插值函数要复杂得多,我不能像您所做的那样在单独的 interp_ 函数中轻松定义它。我无法避免创建数组 list_interpfns 的 for 循环。是否可以使用 df.apply() 使用两个变量(在本例中为 df_sample['a'] 和 df_sample['list_interpfns']
    • 啊,是的,我找到了如何在多列上执行 df.apply()。现在我的代码快了将近 7 倍 :) stackoverflow.com/questions/13331698/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多