假设我有一个DataFrame,其中包含有关山上不同海拔高度温度的数据,每个数据每天同时采样一次。每个探针的高度是固定的(即它们每天保持不变)并且是已知的。每行代表一个不同的时间戳,我有一个单独的列来记录每个探针观察到的温度。我还有一个列(targ_alt
),其中包含每行的“感兴趣的高度”。
我的目标是添加一个名为intreped_temp
的新列,其中包含对于每一行,通过在已知探针的温度之间线性插值来获得该行targ_alt
的温度。高度。这样做的最佳方式是什么?
以下是一些设置代码,因此我们可以查看相同的上下文:
import pandas as pd
import numpy as np
np.random.seed(1)
n = 10
probe_alts = {'base': 1000, 'mid': 2000, 'peak': 3500}
# let's make the temperatures decrease at higher altitudes...just for style
temp_readings = {k: np.random.randn(n) + 15 - v/300 for k, v in probe_alts.items()}
df = pd.DataFrame(temp_readings)
targ_alt = 2000 + (500 * np.random.randn(n))
df['targ_alt'] = targ_alt
所以df
看起来像这样:
base mid peak targ_alt
0 13.624345 10.462108 2.899381 1654.169624
1 11.388244 6.939859 5.144724 1801.623237
2 11.471828 8.677583 4.901591 1656.413650
3 10.927031 8.615946 4.502494 1577.397179
4 12.865408 10.133769 4.900856 1664.376935
5 9.698461 7.900109 3.316272 1993.667701
6 13.744812 8.827572 3.877110 1441.344826
7 11.238793 8.122142 3.064231 2117.207849
8 12.319039 9.042214 3.732112 2829.901089
9 11.750630 9.582815 4.530355 2371.022080
答案 0 :(得分:2)
在我上面给出的示例中,我想要插入每行中的不同x坐标。精细。如果你不...如果你想要插入每一行中相同的x坐标,那么使用SciPy可以节省大量的时间。见下面的例子:
import numpy as np
import pandas as pd
from scipy.interpolate import interp1d
np.random.seed(1)
n = 10e4
df = pd.DataFrame({'a': np.random.randn(n),
'b': 10 + np.random.randn(n),
'c': 30 + np.random.randn(n)})
xs = [-10, 0, 10]
cvs = df.columns.values
现在考虑使用3种不同的方法来处理一个列,该列将在给定列之间插入x坐标为5:
%timeit df['n1'] = df.apply(lambda row: np.interp(5, xs, row[cvs]), axis=1)
%timeit df['n2'] = df.apply(lambda row: np.interp(5, xs, tuple([row[j] for j in cvs])), axis=1)
%timeit df['n3'] = interp1d(xs, df[cvs])(5)
以下是n = 1e2的结果:
100 loops, best of 3: 13.2 ms per loop
1000 loops, best of 3: 1.24 ms per loop
1000 loops, best of 3: 488 µs per loop
对于n = 1e4:
1 loops, best of 3: 1.33 s per loop
10 loops, best of 3: 109 ms per loop
1000 loops, best of 3: 798 µs per loop
对于n = 1e6:
# first one is too slow to wait for
1 loops, best of 3: 10.9 s per loop
10 loops, best of 3: 58.3 ms per loop
一个后续问题:是否有一种快速方法来修改此代码,以便它可以通过线性外推处理训练数据的最小 - 最大范围之外的x输入?
答案 1 :(得分:1)
确定。我实际上有点意外,但这是一个起点。在使用zip
之前,是否有人可以建议我不需要执行np.interp
ping将map
的所有输入压缩到一列的方法? (请参阅下面的编辑。这正是DataFrame.apply
所做的...... )I.e。是否有像map
一样的Pandas函数用于Series,但是将DataFrame的整行作为其输入(但不涉及groupby
)?
这是代码,从问题停止的地方开始:
df['rolled'] = zip(df['targ_alt'], zip(df['base'], df['mid'], df['peak']))
%timeit df['interped_temp'] = df['rolled'].map(lambda x: np.interp(x[0], probe_alts.values(), x[1]))
del df['rolled']
根据需要返回:
base mid peak targ_alt interped_temp
0 13.624345 10.462108 2.899381 1654.169624 11.555706
1 11.388244 6.939859 5.144724 1801.623237 7.822315
2 11.471828 8.677583 4.901591 1656.413650 9.637647
3 10.927031 8.615946 4.502494 1577.397179 9.592617
4 12.865408 10.133769 4.900856 1664.376935 11.050570
5 9.698461 7.900109 3.316272 1993.667701 7.911496
6 13.744812 8.827572 3.877110 1441.344826 11.574613
7 11.238793 8.122142 3.064231 2117.207849 7.726924
8 12.319039 9.042214 3.732112 2829.901089 6.104308
9 11.750630 9.582815 4.530355 2371.022080 8.333099
对于n=10
,%timeit
给出182us / loop。对于n=1e6
,%timeit
给出4.51s /循环。非常好奇看到其他方法。
@DSM做出了很好的评论probe_alts.values()
可以按任何顺序返回。这是一个更清晰的代码,具有上述精神:
probes = ['base', 'mid', 'peak']
df['rolled'] = zip(df['targ_alt'], zip(*[df[p] for p in probes]))
df['interped_temp'] = df['rolled'].map(lambda x: np.interp(x[0], tuple(probe_alts[p] for p in probes), x[1]))
del df['rolled']
这是一个看起来更清洁的方法,只使用DataFrame.apply
,这可能只是更整体......
probes = ['base', 'mid', 'peak']
def cust_interp(row):
return np.interp(row['targ_alt'], tuple(probe_alts[p] for p in probes), row[probes])
df['interped_temp'] = df.apply(cust_interp, axis=1)
答案 2 :(得分:0)
一种方法可能是转置DataFrame,在要插入的行之间插入NaN(缺失值)行,进行插值(填充值),然后转回:
df.transpose()
df.loc['intreped_temp'] = np.nan
# row needs to reside in between data columns for interpolating to work
# may require further index manipulation
df.sort_index()
df.interpolate()
df.transpose()
此策略源自熊猫插值指南中的信息:https://pandas.pydata.org/pandas-docs/dev/user_guide/missing_data.html#interpolation