pandas bfill по интервалу для исправления пропущенных / недействительных записей - PullRequest
1 голос
/ 20 марта 2020

, поэтому у меня есть фрейм данных

df = pandas.DataFrame([[numpy.nan,5],[numpy.nan,5],[2015,5],[2020,5],[numpy.nan,10],[numpy.nan,10],[numpy.nan,10],[2090,10],[2100,10]],columns=["value","interval"])

    value  interval
0     NaN         5
1     NaN         5
2  2015.0         5
3  2020.0         5
4     NaN        10
5     NaN        10
6     NaN        10
7  2090.0        10
8  2100.0        10

Мне нужно заполнить значения NaN в обратном направлении на основе их интервала и первого значения non-nan, следующего за этим индексом, чтобы ожидаемый результат составил

    value  interval
0  2005.0         5  # corrected 2010 - 5(interval)
1  2010.0         5  # corrected 2015 - 5(interval)
2  2015.0         5  # no change ( use this to correct 2 previous rows)
3  2020.0         5  # no change
4  2060.0        10  # corrected 2070 - 10
5  2070.0        10  # corrected 2080 - 10 
6  2080.0        10  # corrected 2090 - 10 
7  2090.0        10  # no change (use this to correct 3 previous rows)
8  2100.0        10  # no change

Я в растерянности относительно того, как я могу выполнить sh эту задачу, используя векторизованные операции pandas / numpy ...

Я могу сделать это с довольно простым l oop

last_good_value = None
fixed_values = []
for val,interval in reversed(df.values):
    if val == numpy.nan and last_good_value is not None:
       fixed_values.append(last_good_value - interval)
       last_good_value = fixed_values[-1]
    else:
       fixed_values.append(val) 
       if val != numpy.nan:
           last_good_value = val

print (reversed(fixed_values))

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

Ответы [ 2 ]

2 голосов
/ 20 марта 2020

Сначала получите положение строк в группах, имеющих одинаковое значение интервала.
Затем получите последнее значение каждой группы.
То, что вы ищете, это "last_value - pos * interval"

df = df.reset_index()
grouped_df = df.groupby(['interval'])
df['pos'] = grouped_df['index'].rank(method='first', ascending=False) - 1 
df['last'] = grouped_df['value'].transform('last')
df['value'] = df['last'] - df['interval'] * df['pos']
del df['pos'], df['last'], df['index']
1 голос
/ 20 марта 2020

Создайте серию группировки, которая группирует последнее ненулевое значение со всеми NaN строками перед ним, обращаясь к [::-1]. Затем вы можете bfill и использовать cumsum, чтобы определить, сколько нужно вычесть из каждой строки.

s = df['value'].notnull()[::-1].cumsum()
subt = df.loc[df['value'].isnull(), 'interval'][::-1].groupby(s).cumsum()

df['value'] = df.groupby(s)['value'].bfill().subtract(subt, fill_value=0)

    value  interval
0  2005.0         5
1  2010.0         5
2  2015.0         5
3  2020.0         5
4  2060.0        10
5  2070.0        10
6  2080.0        10
7  2090.0        10
8  2100.0        10

Поскольку subt является подмножеством только NaN строк, fill_value=0 гарантирует, что строки со значениями останутся неизменными

print(subt)
#6    10
#5    20
#4    30
#1     5
#0    10
#Name: interval, dtype: int64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...