我有一个包含许多列的大数据框。为简单起见,可以说:
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之类的东西),那么我相信它可以减少操作时间。您能提供其他选择吗?
答案 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