Python Pandas заполнить оператором if? - PullRequest
1 голос
/ 30 апреля 2020

У меня есть следующие временные ряды, измеряющие изменения между начальной и конечной точкой в ​​двух столбцах. Я хотел бы вычислить столбец l, используя векторизованный подход вместо итеративного в Pandas, записывающего путь от начала до конца. Есть простой способ вычислить столбец, пожалуйста? ffill() и другие приемы заполнения наивно не решают пустоту между начальной и конечной позицией. Есть ли способ обусловить ffill/bfill, чтобы помочь решить эту проблему?

Примечание: s и e соответствуют начальной и конечной позициям. Я хочу построить последовательность, в которой l находится только между позициями s и e, но не включает в себя начальную позицию (и не включает там, где нет начала и конца).

Пример, показанный ниже , строки 0-2 мы хотим заполнить l теми, которые исключают самое первое. Также хочу быть уверенным, что у нас не будет строк для строк, пока у нас не появится еще один s.

    s   e   l
0   1.0 NaN NaN
1   NaN NaN 1.0
2   NaN 1.0 1.0
3   NaN NaN NaN
4   NaN NaN NaN
5   NaN NaN NaN
6   NaN NaN NaN
7   1.0 NaN NaN
8   1.0 1.0 1.0
9   1.0 1.0 1.0
10  1.0 1.0 1.0
11  NaN 1.0 1.0
12  NaN NaN NaN
13  NaN NaN NaN

Спасибо, и помощь очень ценится!

1 Ответ

5 голосов
/ 30 апреля 2020

Хороший подход к этим трудным для векторизации проблемам - это go с numba. При использовании numba код компилируется до C-level, поэтому он должен очень хорошо работать на больших фреймах данных. Уточняя типы numba в сигнатуре, мы получаем своевременную компиляцию и еще больше повышаем производительность. Здесь я устанавливаю тип входа на float64, для другого входа dtype меняем соответственно.

from numba import njit, float32

@njit('float32[:](float64[:,:])')
def ffill_conditional(a):
    flag_col0 = 0
    out = np.full(a.shape[0], fill_value=np.nan, dtype=float32)
    for i in range(a.shape[0]):
        if a[i,0]==1. and flag_col0==0:
            flag_col0 = 1
            from_col0 = i+1
        elif a[i,1]==1 and np.isnan(a[i+1,1]) and flag_col0==1:
            till_col1 = i+1
            out[from_col0:till_col1] = 1.
            flag_col0=0
    return out

Проверка на общем примере:

a = df.values[:,:2]
df['l'] = ffill_conditional(a)

print(df)

     s    e    l
0   1.0  NaN  NaN
1   NaN  NaN  1.0
2   NaN  1.0  1.0
3   NaN  NaN  NaN
4   NaN  NaN  NaN
5   NaN  NaN  NaN
6   NaN  NaN  NaN
7   1.0  NaN  NaN
8   1.0  1.0  1.0
9   1.0  1.0  1.0
10  1.0  1.0  1.0
11  NaN  1.0  1.0
12  NaN  NaN  NaN
13  NaN  NaN  NaN
...