简化Python中数据插值的数据存储
我有20多个表格,跟表格1差不多。表格里的字母代表实际的数值。
Table 1:
$ / cars |<1 | 2 | 3 | 4+
<10,000 | a | b | c | d
20,000 | e | f | g | h
30,000 | i | j | k | l
40,000+ | m | n | o | p
用户输入的值可能是(2.4, 24594),这个值是在f、g、j和k之间的。我的Python函数定义和计算这个双线性插值的伪代码如下。
def bilinear_interpolation( x_in, y_in, x_high, x_low, y_low, y_high ):
# interpolate with respect to x
# interpolate with respect to y
# return result
我应该怎么存储表格1的数据(用文件、字典、元组的元组,还是字典的列表),这样才能最有效和正确地进行双线性插值呢?
3 个回答
双线性插值并没有什么特别之处,也并不是说你的使用情况很奇怪;你只需要进行两次查找(对于完整的行/列存储单元)或者四次查找(对于数组类型的存储)。最有效的方法取决于你访问数据的方式和数据的结构。
如果你的例子确实是典型的,只有16个条目,你可以随便存储它,速度对于任何正常的负载来说都足够快。
我会把第一列的数据整理成一个有序的列表,然后使用标准库里的 bisect
模块来查找这些值——这样可以最快找到比目标值小的和大的索引。其他列的数据可以用一个和这个列表平行的列表来保存。
如果你想要一个计算效率最高的解决方案,并且不受标准库的限制,我推荐使用scipy和numpy。首先,把a到p的数组存成一个二维的numpy数组,然后把$4k-10k和1-4的数组存成一维的numpy数组。如果这两个一维数组都是单调递增的,可以用scipy的interpolate.interp1d;如果不是,而且你的示例数组和例子一样小,可以用interpolate.bsplrep(双变量样条表示法)。当然,你也可以自己写一个,不用管scipy。以下是一些例子:
# this follows your pseudocode most closely, but it is *not*
# the most efficient since it creates the interpolation
# functions on each call to bilinterp
from scipy import interpolate
import numpy
data = numpy.arange(0., 16.).reshape((4,4)) #2D array
prices = numpy.arange(10000., 50000., 10000.)
cars = numpy.arange(1., 5.)
def bilinterp(price,car):
return interpolate.interp1d(cars, interpolate.interp1d(prices, a)(price))(car)
print bilinterp(22000,2)
我上次检查(大约是2007年的一个版本的scipy)时,它只适用于x和y都是单调递增的数组。
对于像这个4x4的小数组,我觉得你应该使用这个: http://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.bisplrep.html#scipy.interpolate.bisplrep 这个方法可以处理形状更复杂的表面,而且这个函数只需要创建一次。对于更大的数组,我觉得你应该用这个(不确定它是否有和interp1d一样的限制): http://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp2d.html#scipy.interpolate.interp2d 不过这两个方法都需要比上面三个数组更复杂的数据结构。