Засыпать значения путем распределения значений по предыдущим NaN во временных сериях с пандами - PullRequest
0 голосов
/ 09 мая 2018

У меня есть временной ряд, где каждое наблюдение представляет собой общее количество чего-либо со времени последнего наблюдения. Если в этом временном шаге нет наблюдения, тогда значение сообщается как NaN. Пример формата:

Timestep  Value
1          10
2          NaN
3          NaN
4          9
5          NaN
6          NaN
7          NaN
8          16
9          NaN
10         NaN

Что я хотел бы сделать, так это распределить наблюдаемые значения по NaN перед этим. Например, последовательность типа [5, NaN, NaN, 6] станет [5, 2, 2, 2] с последним наблюдением 6, распределенным по последним 2 значениям NaN. Применительно к кадру данных выше желаемый результат будет:

Timestep  Value
1          10
2          3
3          3
4          3
5          4
6          4
7          4
8          4
9          NaN
10         NaN

Я пытался сделать это с некоторыми методами обратной засыпки и интерполяции панд, но не нашел ничего, что вполне соответствует тому, что я хочу.

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Подсчитайте совокупный NA, тогда мы сделаем update

s=df.Value.notnull().cumsum().shift(1)
df.Value.update(df.Value.bfill()/s.groupby(s).transform('count'))
df
Out[885]: 
   Timestep  Value
0         1   10.0
1         2    3.0
2         3    3.0
3         4    3.0
4         5    4.0
5         6    4.0
6         7    4.0
7         8    4.0
8         9    NaN
9        10    NaN
0 голосов
/ 09 мая 2018

transform

df.Value.bfill().div(
    df.groupby(df.Value.notna()[::-1].cumsum()).Value.transform('size')
)

0    10.0
1     3.0
2     3.0
3     3.0
4     4.0
5     4.0
6     4.0
7     4.0
8     NaN
9     NaN
Name: Value, dtype: float64

np.bincount и pd.factorize

a = df.Value.notna().values
f, u = pd.factorize(a[::-1].cumsum()[::-1])

df.Value.bfill().div(np.bincount(f)[f])

0    10.0
1     3.0
2     3.0
3     3.0
4     4.0
5     4.0
6     4.0
7     4.0
8     NaN
9     NaN
Name: Value, dtype: float64

Альтернативная более короткая версия. Это работает, потому что cumsum естественно дает мне то, что делает factorize.

a = df.Value.notna().values[::-1].cumsum()[::-1]
df.Value.bfill().div(np.bincount(a)[a])

Подробнее

В обоих приведенных выше вариантах нам нужно определить, где находятся нулевые значения, и использовать cumsum в обращенном ряду для определения групп. В опции transform я использую groupby и size для подсчета размера этих групп.

Второй вариант использует подсчет и нарезку бинов для получения одной и той же серии.

Спасибо @ScottBoston за напоминание о необходимости упомянуть обратный элемент [::-1]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...