我有以下pd数据框。
import pandas as pd
df = pd.DataFrame([pd.datetime(2016,1,1), pd.datetime(2016,2,1)], columns = ['d1'])
df['d2'] = [pd.datetime(2016,1,5), pd.datetime(2016,2,10)]
df['d3'] = [pd.datetime(2016,1,10), pd.datetime(2016,2,20)]
df['v1'], df['v2'], df['v3'] = [1,10], [5, 100], [5, 100]
df['x1'] = [pd.datetime(2016,1,2), pd.datetime(2016,2,13)]
d1 d2 d3 v1 v2 v3 x1
0 2016-01-01 2016-01-05 2016-01-10 1 5 5 2016-01-02
1 2016-02-01 2016-02-10 2016-02-20 10 100 100 2016-02-13
我想通过插值计算列x2
x: x1
independent = [d1, d2, d3]
dependent = [v1, v2, v3]
在上面的示例中,x2对于行0应为2,对于行1应为100。
我可以考虑使用df.iterrows(),slice [d1-d3]和[v1-v3],然后使用np.interp,但即使这样也有点复杂,因为我必须将日期转换为float。 (np.interp仅获取浮动列表)。
熊猫队应该有一个更清洁,更具矢量化的方法吗?
答案 0 :(得分:1)
我不知道Pandas是否可以使用特定列作为IV和DV进行插值。但是,如果您将时间戳视为单个系列,则可以获得所需的内容。
通过稍微改组,我们可以重新格式化interpolate(method='time')
的数据帧,然后将其恢复为原始格式。从示例数据框开始,添加一个空的x2
:
import numpy as np
df['x2'] = np.nan
df
d1 d2 d3 v1 v2 v3 x1 x2
0 2016-01-01 2016-01-05 2016-01-10 1 5 5 2016-01-02 NaN
1 2016-02-01 2016-02-10 2016-02-20 10 100 100 2016-02-13 NaN
现在从宽到长摆动,并缩减为两列,d
和v
(x
获得d
和v
的荣誉会员资格现在的俱乐部)。将实际列名保存为索引:
pairs = [('d1','v1'), ('d2','v2'), ('d3','v3'), ('x1','x2')]
df2 = pd.concat(
(df[[d, v]].rename(index=lambda i: d,
columns=lambda x: 'd' if (x[0]=='d') | (x=='x1') else 'v') for d, v in pairs))
df2
d v
d1 2016-01-01 1.0
d1 2016-02-01 10.0
d2 2016-01-05 5.0
d2 2016-02-10 100.0
d3 2016-01-10 5.0
d3 2016-02-20 100.0
x1 2016-01-02 NaN
x1 2016-02-13 NaN
我们希望基于时间interpolate
,因此我们将时间戳移动到索引中,按日期排序,然后执行插值:
df3 = (df2.reset_index()
.set_index(pd.to_datetime(df2.d))
.drop('d', 1)
.sort_index()
.interpolate(method="time")
.sort_values('index')
)
df3
index v
d
2016-01-01 d1 1.0
2016-02-01 d1 10.0
2016-01-05 d2 5.0
2016-02-10 d2 100.0
2016-01-10 d3 5.0
2016-02-20 d3 100.0
2016-01-02 x1 2.0
2016-02-13 x1 100.0
根据OP预期输出,插值是正确的。现在我们只需要将数据框恢复到原始形状。我们通过将索引设置回0
/ 1
,基于奇数/偶数行数,然后使用pivot()
来执行此操作:
df4 = df3.reset_index().rename(index=lambda x: int(x%2)).pivot(columns='index')
df4.columns = df4.columns.droplevel(0)
iv, dv = zip(*pairs)
df4.columns = iv + dv
df4
d1 d2 d3 x1 v1 v2 v3 x2
0 2016-01-01 2016-01-05 2016-01-10 2016-01-02 1.0 5.0 5.0 2.0
1 2016-02-01 2016-02-10 2016-02-20 2016-02-13 10.0 100.0 100.0 100.0
可能有一种更为隐蔽的方式来重塑中间的东西,但这里的关键直觉是,如果给出正确的格式,Pandas会使用时间作为参考来插入缺失值。
更新(每条评论)
如果插值必须按行进行,我们可以使用与上面类似的方法,apply()
:
def custom_interp(row, pairs):
data = pd.concat(
(pd.DataFrame(row[[d, v]]).rename(index=lambda x: 'd' if (x[0] == 'd') | (x == 'x1') else 'v',
columns=lambda x: d) for d, v in pairs),
axis=1).T.reset_index()
data = (data.set_index(pd.to_datetime(data.d))
.drop('d', 1)
.sort_index()
)
data.v = data.v.astype(float)
data = data.interpolate(method='time').reset_index()
data.index = np.repeat(row.name, len(data.index))
data = data.pivot(columns='index')
data.columns = data.columns.droplevel(0)
return data.values[0]
df.apply(custom_interp, args=(pairs,), axis=1)
d1 d2 d3 v1 v2 v3 x1 x2
0 2016-01-01 2016-01-05 2016-01-10 2016-01-02 1.0 5.0 5.0 2.0
1 2016-02-01 2016-02-10 2016-02-20 2016-02-13 10.0 100.0 100.0 100.0