在数据框中使用多个插值功能

时间:2019-04-24 12:14:15

标签: python loops interpolation

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

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

我需要在df_sample中定义一个新列(例如列'b'),该列需要使用一些插值函数,其插值函数将从列'a'中获取。

现在,问题在于每一行的插值函数都不同。对于每一行,我从不同的1D网格进行插值;所以我对每一行都有不同的插值功能。因此,我要做的是事先生成这些插值函数并将它们存储到数组中。仅举一个例子,显示下面的代码以生成示例数组'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之类的东西),那么我相信它可以减少操作时间。您能提供其他选择吗?

1 个答案:

答案 0 :(得分:1)

请考虑避免多个for循环和簿记,以初始化和更新数组和序列,并使用Series.apply()将列值传递给函数build和function参数:

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