首页 > 解决方案 > 用numpy的限制填充

问题描述

出于性能原因,我想使用 Numpy 进行与 Pandas 相同的前向填充,如下所示:

s = pd.Series([1, 2, nan, nan, nan, 7, 8, nan, nan, nan, nan, nan, nan, nan, nan])
s.ffill(limit=7)

这导致:

array([ 1., 2., 2., 2., 2., 7., 8., 8., 8., 8., 8., 8., 8., 8., nan])

我有一个无限制的前向填充但这对我来说不起作用。

标签: pythonnumpy

解决方案


基本上结合了这两个来源的解决方案:

并为超过阈值限制的索引添加了分配:

arr = np.array([1, 2, np.nan, np.nan, np.nan, 7, 8, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan])
limit = 7

mask = np.isnan(arr)
idx = np.where(~mask, np.arange(mask.size), False)

# Create an array that is 1 where idx is 0, and pad each end with an extra 0.
isnonzero = np.concatenate(([0], np.equal(idx, 0).view(np.int8), [0]))
absdiff = np.abs(np.diff(isnonzero))

# pair-wise indices for consecutive zero ranges
ranges = np.flatnonzero(absdiff == 1)

# add to_begin padding to get overflow and ranges equal size
overflow = np.ediff1d(ranges, to_begin=0) - limit
overflow_mask = overflow > 0

# do the actual fill
arr = arr[np.maximum.accumulate(idx)]

# reassign overflowed elements to nan
arr[ranges[overflow_mask] - overflow[overflow_mask]] = np.nan 

输出:

array([ 1.,  2.,  2.,  2.,  2.,  7.,  8.,  8.,  8.,  8.,  8.,  8.,  8., 8., nan])

仅使用给定的示例对其进行了测试,因此可能存在一些不一致之处。

编辑

请注意,这只会设置第一个超出的元素,因此可能不是您正在寻找的解决方案。我试图重塑ranges(-1,2)就地修改第一个轴上的每个范围,使其成为相应溢出的切片。这确实有效,但我没有运气尝试将 2d 切片分配回arr.

# pair-wise indices for consecutive zero ranges
ranges = np.flatnonzero(absdiff == 1).reshape(-1,2)

overflow = np.diff(ranges) - limit
overflow_mask = overflow > 0
# modify ranges so overflowing ranges is a slice over the corresponding overflow
ranges[None,:,0][overflow_mask.T] = ranges[None,:,1][overflow_mask.T] - overflow[overflow_mask]

推荐阅读