How to ffill nan values in a numpy array using the last non-nan values repeating N times

wuya

I would like to ffill nan values in a numpy array using the last non-nan values repeating N times. If the number of nan values > N, then fill the rest nan values with zero. How do I do it in pure numpy without iteration?

import numpy as np

n = 2
arr = np.array([np.nan, 0, 0, np.nan, 5, 4, 4, np.nan, np.nan, np.nan, 1, 5, 3, np.nan, 2, np.nan, np.nan])

def ffill(arr: np.array, n: int):
    pass
    return arr

result = np.array([0.0, 0.0, 0.0, 0.0, 5.0, 4.0, 4.0, 4.0, 4.0, 0.0, 1.0, 5.0, 3.0, 3.0, 2.0, 2.0, 2.0])

Ffill 4 n times (=2) [... 4, np.nan, np.nan, np.nan ...] -> [... 4, 4, 4, 0 ...]

[Solution]

Thanks for @Homer512 's answer. I improved it when n is very large.

def ffill(arr: np.array, n: int):
    if np.isnan(arr[0]):
        arr[0] = 0

    isnan = np.isnan(arr)
    notnan = ~isnan
    valid = arr[notnan]
    indices = np.cumsum(notnan) - 1
    arr = valid[indices]

    overlimit = np.lib.stride_tricks.sliding_window_view(isnan[:-1][::-1], isnan.size-n)[:, ::-1].all(axis=0)
    overlimit &= isnan[n:]

    indices = np.flatnonzero(overlimit) + n
    arr[indices] = 0
    return arr
Homer512

Here is a trick that works:

  1. Fix the start value
if math.isnan(arr[0]):
    arr[0] = 0
  1. Now we can keep track of the valid indices with np.cumsum
isnan = np.isnan(arr)
notnan = ~isnan
valid = arr[notnan]
indices = np.cumsum(notnan) - 1
arr = valid[indices]
  1. To support your requirement that NaNs are replaced with zeros after N steps, you could use np.convolve(isnan, (1,) * (n + 1), mode='same') > n to find the indices. But because convolve is centered, it's a bit complicated to find the correct index from the convolution. Let's do it manually instead. Yes, this will use an iteration, but only a fixed number for N
overlimit = np.copy(isnan[n:])
for i in range(1, n + 1):
    overlimit &= isnan[n-i:-i]
indices = np.flatnonzero(overlimit) + n
arr[indices] = 0

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

how to find the unique non nan values in a numpy array?

Extrapolate NaN values in a numpy array

Interpolate NaN values in a numpy array

Checking nan values in a numpy array

Get two neighboring non-nan values in numpy array

Count non-nan-values in 3d numpy array

Pandas and Numpy consecutive non Nan values

How do I find the coordinates of nan values in a numpy array?

How to change all string values in a multidimensional numpy array to NaN?

Count number of non-nan values in array

Reverse sort of Numpy array with NaN values

Replace values in numpy array containing NaN

numpy array: replace nan values with average of columns

Numpy: multiplying with NaN values without using nan_to_num

How to extract non nan values from a dataframe

How to set a range of values in numpy to nan?

Convert python list with None values to numpy array with nan values

How to change consecutive repeating values in pandas dataframe series to nan or 0?

Locate first and last non NaN values in a Pandas DataFrame

Conditional loop through dataframe rows with last non NAN values

How to return non-repeating values in an array?

How to return a dataframe with the last non-NaN values in each column for each month?

repeating a numpy array N times

index of non "NaN" values in Pandas

How to check for NaN values

Keep only the value in the last non-nan column, set all other values to nan (fast solution)

Merging non NaN values values only

Checking if np.nan is inside an array returns non expected values

Set all non min values to NaN in a 2D array