【问题标题】:Creating a custom interpolation function for pandas为 pandas 创建自定义插值函数
【发布时间】:2017-01-27 14:07:40
【问题描述】:

我目前正在尝试使用 pandas 清理和填充一些缺失的时间序列数据。 interpolate 函数工作得很好,但是它没有我的数据集所需的一些(不太广泛使用的)插值函数。有几个例子是一个简单的“最后一个”有效数据点,它会创建类似于阶跃函数的东西,或者类似于对数或几何插值的东西。

浏览文档,似乎没有办法传递自定义插值函数。这样的功能是否直接存在于 pandas 中?如果没有,有没有人做过任何 pandas-fu 以通过其他方式有效地应用自定义插值?

【问题讨论】:

  • 对于重用最后一个有效值的特定情况,您将使用ffill。通常,您可以将apply 用于此类目的,或者只是对各个系列进行一些魔术并将它们重新分配给您的数据框。您还缺少什么?
  • 具体问题 - 我的数据集在缺失数据中并不完全“干净”。这里或那里可能缺少 1 或 2 个值,然后是 1000 个好的值,然后是 20 个缺失值的块。识别这些边界并应用一个函数,该函数将之前的非缺失值和之后的非缺失值作为输入,这让我很头疼。

标签: python pandas interpolation


【解决方案1】:

Pandas 提供的插值方法是 scipy.interpolate.interp1d 提供的方法 - 不幸的是,它们似乎无法以任何方式扩展。我必须做类似的事情来应用 SLERP 四元数插值(使用numpy-quaternion),并且我设法非常有效地做到了。我会在这里复制代码,希望您可以根据自己的目的对其进行调整:

def interpolate_slerp(data):
    if data.shape[1] != 4:
        raise ValueError('Need exactly 4 values for SLERP')
    vals = data.values.copy()
    # quaternions has size Nx1 (each quaternion is a scalar value)
    quaternions = quaternion.as_quat_array(vals)
    # This is a mask of the elements that are NaN
    empty = np.any(np.isnan(vals), axis=1)
    # These are the positions of the valid values
    valid_loc = np.argwhere(~empty).squeeze(axis=-1)
    # These are the indices (e.g. time) of the valid values
    valid_index = data.index[valid_loc].values
    # These are the valid values
    valid_quaternions = quaternions[valid_loc]
    # Positions of the missing values
    empty_loc = np.argwhere(empty).squeeze(axis=-1)
    # Missing values before first or after last valid are discarded
    empty_loc = empty_loc[(empty_loc > valid_loc.min()) & (empty_loc < valid_loc.max())]
    # Index value for missing values
    empty_index = data.index[empty_loc].values
    # Important bit! This tells you the which valid values must be used as interpolation ends for each missing value
    interp_loc_end = np.searchsorted(valid_loc, empty_loc)
    interp_loc_start = interp_loc_end - 1
    # These are the actual values of the interpolation ends
    interp_q_start = valid_quaternions[interp_loc_start]
    interp_q_end = valid_quaternions[interp_loc_end]
    # And these are the indices (e.g. time) of the interpolation ends
    interp_t_start = valid_index[interp_loc_start]
    interp_t_end = valid_index[interp_loc_end]
    # This performs the actual interpolation
    # For each missing value, you have:
    #   * Initial interpolation value
    #   * Final interpolation value
    #   * Initial interpolation index
    #   * Final interpolation index
    #   * Missing value index
    interpolated = quaternion.slerp(interp_q_start, interp_q_end, interp_t_start, interp_t_end, empty_index)
    # This puts the interpolated values into place
    data = data.copy()
    data.iloc[empty_loc] = quaternion.as_float_array(interpolated)
    return data

诀窍在于np.searchsorted,它可以很快找到每个值的正确插值结束。这种方法的局限性在于:

  • 您的插值函数必须在某种程度上quaternion.slerp 一样工作(这应该不奇怪,因为它具有常规的 ufunc 广播行为)。
  • 它只适用于每端只需要一个值的插值方法,所以如果你想要例如诸如三次插值之类的东西(你不这样做,因为已经提供了)这是行不通的。

【讨论】:

  • 说不想做三次样条曲线过于简单了——我特地来这里是因为我有一个特定的局部单调性保持样条曲线。
  • @EliS 所以你想要一个不同于 SciPy 已经提供的三次插值?也许你可以提出一个关于你到底需要什么的新问题(如果你想指出为什么这个答案对你不起作用)。
【解决方案2】:

为了找到Series 中的缺失数据块,您可以按照Finding consecutive segments in a pandas data frame 的方式进行操作:

s = pd.Series([1, 2, np.nan, np.nan, 5, 6, np.nan, np.nan, np.nan, 10])
x = s.isnull().reset_index(name='null')
# computes unique numbers for each block of consecutive nan/non-nan values
x['block'] = (x['null'].shift(1) != x['null']).astype(int).cumsum()
# select those blocks that relate to null values
x[x['null']].groupby('block')['index'].apply(np.array)

这将导致以下系列,其中值是所有索引条目的数组,其中包含每个块的 nan 值:

block
2       [2, 3]
4    [6, 7, 8]
Name: index, dtype: object

您可以迭代这些并应用自定义修复逻辑。那么在之前和之后获取值应该很容易。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-28
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多