Заполнение массива последующим значением

#python #arrays #python-2.7 #pandas #numpy

#python #массивы #python-2.7 #pandas #numpy

Вопрос:

В моем фрейме данных я получу столбец, который содержит всего несколько значений, отличных от nan. Я хочу использовать значения, отличные от nan, в качестве группирующих переменных для всех предыдущих строк, которые содержат значение NaN. Чтобы имитировать это, я создал следующий массив:

 count = np.array([np.NaN,np.NaN,np.NaN,3,np.NaN,np.NaN,6,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,12])
count = Series(count)
  

Для этого массива я смог создать функцию заполнения

 def pad_expsamp_time(array):
    sect = np.zeros(array.size) # create array filled with zeros
    inds = array.index[array.notnull()] # select the non-zero values
    rev_inds = inds[::-1] # sort high to low
    # fill array with value until index of value. Repeat for lower values. 
    for i in rev_inds: 
        sect[:i] = i
    return Series(sect)
  

Эта функция работает, когда она может предположить, что индексы значений, отличных от nan, равны фактическим значениям. Однако, как я могу заполнить массив, когда индексы не равны содержимому?


Например, что, если количество массивов равно:

 count = np.array([np.NaN,np.NaN,np.NaN,1,np.NaN,np.NaN,2,np.NaN,np.NaN,np.NaN,np.NaN,np.NaN,3])
  

И желаемый результат

 count = np.array([1,1,1,1,2,2,2,3,3,3,3,3,3]
  

Возможно, что в конце массива есть NAN. Я бы хотел, чтобы они оставались NANS, чтобы фрейм данных игнорировал их.

 count = np.array([np.NaN,np.NaN,np.NaN,1,np.NaN,np.NaN,2,np.NaN,np.NaN,3,np.NaN,np.NaN]) 
# Will become:
count = np.array([1,1,1,1,2,2,2,3,3,3,np.nan,np.nan]
  

Комментарии:

1. Может ли последний элемент быть NaN ?

2. @Divakar да, это действительно могло бы

3. Итак, вам нужно, чтобы он был чем-то заполнен? Если да, то чем мы должны его заполнить? Может быть, добавить примерный пример?

Ответ №1:

IIUC вы можете просто использовать метод pandas bfill():

ваш пример:

 In [89]: s = pd.Series(np.array([np.nan,np.nan,np.nan,1,np.nan,np.nan,2,np.nan,np.nan,3,np.nan,np.nan]))

In [90]: s
Out[90]:
0     NaN
1     NaN
2     NaN
3     1.0
4     NaN
5     NaN
6     2.0
7     NaN
8     NaN
9     3.0
10    NaN
11    NaN
dtype: float64

In [91]: s.bfill()
Out[91]:
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     2.0
6     2.0
7     3.0
8     3.0
9     3.0
10    NaN
11    NaN
dtype: float64
  

Примеры Divakar:

 In [81]: s = pd.Series(array([ nan,  nan,  nan,   6.,  nan,  nan,   5.,  nan,  nan,  nan,  nan, nan,   2.]))

In [82]: s
Out[82]:
0     NaN
1     NaN
2     NaN
3     6.0
4     NaN
5     NaN
6     5.0
7     NaN
8     NaN
9     NaN
10    NaN
11    NaN
12    2.0
dtype: float64

In [83]: s.bfill()
Out[83]:
0     6.0
1     6.0
2     6.0
3     6.0
4     5.0
5     5.0
6     5.0
7     2.0
8     2.0
9     2.0
10    2.0
11    2.0
12    2.0
dtype: float64

In [84]: s = pd.Series(array([ nan,  nan,  nan,   1.,  nan,  nan,   2.,  nan,  nan,  nan,  nan, nan, 3.]))

In [85]: s.bfill()
Out[85]:
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     2.0
6     2.0
7     3.0
8     3.0
9     3.0
10    3.0
11    3.0
12    3.0
dtype: float64

In [86]: s = pd.Series(array([ nan, nan, nan, 1., nan, nan, 2., nan, nan, 3., nan, nan]))

In [87]: s.bfill()
Out[87]:
0     1.0
1     1.0
2     1.0
3     1.0
4     2.0
5     2.0
6     2.0
7     3.0
8     3.0
9     3.0
10    NaN
11    NaN
dtype: float64
  

Комментарии:

1. @Divakar, ИМО, это довольно стандартная операция Pandas, так что здесь нет никакой магии 😉

2. Вау? Действительно? Все проблемы напрасны, ха-ха. Если бы я только знал раньше. Теперь я также могу прекратить писать функцию прямого заполнения…

Ответ №2:

Вот векторизованный подход —

 # Append False at either sides of NaN mask as we try to find start amp;
# stop of each NaN interval by looking for rising and falling edges
mask = np.hstack((False,np.isnan(count),False))
start = np.flatnonzero(mask[1:] > mask[:-1])
stop = np.flatnonzero(mask[1:] < mask[:-1])
lens = stop - start

# Account for NaNs if any at the end of input that might throw off stop values
stop = stop.clip(max=count.size-1)

# Assign values
count[mask[1:-1]] = count[stop].repeat(lens)
  

Пример выполнения —

Случай # 1 :

 In [103]: count
Out[103]: 
array([ nan,  nan,  nan,   6.,  nan,  nan,   5.,  nan,  nan,  nan,  nan,
        nan,   2.])

In [104]:  # Listed code ...

In [105]: count
Out[105]: array([ 6.,  6.,  6.,  6.,  5.,  5.,  5.,  2.,  2.,  2.,  2.,  2.,  2.])
  

Случай # 2 :

 In [118]: count
Out[118]: 
array([ nan,  nan,  nan,   1.,  nan,  nan,   2.,  nan,  nan,  nan,  nan,
        nan,   3.])

In [119]:   # Listed code ...

In [120]: count
Out[120]: array([ 1.,  1.,  1.,  1.,  2.,  2.,  2.,  3.,  3.,  3.,  3.,  3.,  3.])
  

Случай # 3 :

 In [114]: count
Out[114]: 
array([ nan,  nan,  nan,   1.,  nan,  nan,   2.,  nan,  nan,   3.,  nan,
        nan])

In [115]:   # Listed code ...

In [116]: count
Out[116]: 
array([  1.,   1.,   1.,   1.,   2.,   2.,   2.,   3.,   3.,   3.,  nan,
        nan])
  

Комментарии:

1. Удивительно! Большое вам спасибо!