pandas interpolation:使用np.interp更改值

时间:2016-02-02 19:47:55

标签: python pandas scipy

我有300万行数据框,其中包含不同的值:

d    a0    a1    a2
0.5    10.0    5.0    1.0
0.8    10.0    2.0    0.0

我想用(a0,a1,a2)的线性插值填充第四列,该插值取“d”情况下的值,

d    a0    a1    a2    newcol
1.5    10.0    5.0    1.0    3.0
0.8    10.0    2.0    0.0    3.6

newcol是[int(d)]和[int(d + 1)]之间的加权平均值,例如当d = 0.8时,newcol = 0.2 * a0 + 0.8 * a1因为0.8是0到1之间的80%

我发现可以使用np.interp,但是我没办法将三个列名放在变量中:

df["newcol"]=np.interp(df["d"],[0,1,2], [100,200,300])

确实会给我

d    a0    a1    a2    newcol
1.5    10.0    5.0    1.0    250.0
0.8    10.0    2.0    0.0    180.0

但我无法指定值向量发生变化:

df["newcol"]=np.interp(df["d"],[0,1,2], df[["a0","a1","a2"]])

给我以下追溯:

  

文件“C:\ Python27 \ lib \ site-packages \ numpy \ lib \ function_base.py”,第1271行,在interp中   return compiled_interp(x,xp,fp,left,right)   ValueError:对象太深,不适合所需的数组

有没有办法在每一行使用不同的矢量值?你能想到任何解决方法吗?

基本上,我找不到根据定义创建这个新列的方法:

  

x =列“d”中的值是分段线性的函数   在给定点之间,这些点的值在“ai”列中描述

编辑:以前,我使用了scipy.interp1d,这不是内存效率,评论帮我部分解决了我的问题

Edit2:

我尝试了ev-br的方法,声明我必须尝试自己编写循环。

for i in range(len(tps)):
    columns=["a1","a2","a3"]
    length=len(columns)
    x=np.maximum(0,np.minimum(df.ix[i,"d"],len-2))
    xint = np.int(x)
    xfrac = x-xint
    name1=columns[xint]
    name2=columns[xint+1]
    tps.ix[i,"Multiplier"]=df.ix[i,name1]+xfrac*(df.ix[i,name2]-tps.ix[i,name1])  

上面的循环每秒循环50次左右,所以我想我有一个主要的优化问题。我在DataFrame上工作的哪个部分做错了?

2 个答案:

答案 0 :(得分:0)

可能有点太晚了,但我会使用np.interpolate和pandas'应用功能。在您的示例中创建DataFrame:

t = pd.DataFrame([[1.5,10,5,1],[0.8,10,2,0]], columns=['d', 'a0', 'a1', 'a2'])

然后是apply函数:

t.apply(lambda x: np.interp(x.d, [0,1,2], x['a0':]), axis=1)

产生:

0    3.0
1    3.6
dtype: float64

这完全适用于"普通"数据集。但是,DataFrame的大小可能需要更好/更优化的解决方案。处理时间线性缩放,我的机器以每秒10000行的速度计时,这意味着3百万的时间为5分钟......

答案 1 :(得分:0)

好的,我有第二个解决方案,它使用了numexpr模块。这种方法更具体,但也更快。我已经测量了100万行需要733毫秒的完整过程,这还不错......

所以我们像以前一样拥有原始的DataFrame:

t = pd.DataFrame([[1.5,10,5,1],[0.8,10,2,0]], columns=['d', 'a0', 'a1', 'a2'])

我们导入模块并使用它,但它要求我们将两个情况分开,我们将使用'a0'和'a1'或'a1'和'a2'作为线性插值的下限/上限。我们还准备了数字,以便它们可以被馈送到相同的评估(因此-1)。我们通过创建具有插值(最初:'d')的3个数组和限制来实现,具体取决于“d”的值。所以我们有:

import numexpr as ne

lim = np.where(t.d > 1, [t.d-1, t.a1, t.a2], [t.d, t.a0, t.a1])

然后我们评估简单的线性插值表达式,最后将其添加为新的列:

x = ne.evaluate('(1-x)*a+x*b', local_dict={'x': lim[0], 'a': lim[1], 'b': lim[2]})
t['IP'] = np.where(t.d > 1, x+1, x)