Как векторизировать код панды, где он зависит от предыдущей строки?

#python #pandas #numpy-ndarray

Вопрос:

Я пытаюсь векторизовать фрагмент кода в панд:

У меня есть фрейм данных pandas, сгенерированный следующим образом:

идентификаторы ftest валс
0 Q52EG 0 0
1 Q52EG 0 1
2 Q52EG 1 2
3 Q52EG 1 3
4 Q52EG 1 4
5 QQ8Q4 0 5
6 QQ8Q4 0 6
7 QQ8Q4 1 7
8 QQ8Q4 1 8
9 QVIPW 1 9

Если какой-либо идентификатор в ids столбце имеет значение 1 в ftest столбце, то все последующие строки с одинаковым идентификатором должны быть помечены как 1 в has_hist столбце, и это не зависит от текущего ftest значения, как показано в приведенном ниже кадре данных:

идентификаторы ftest валс has_hist
0 Q52EG 0 0 0
1 Q52EG 0 1 0
2 Q52EG 1 2 0
3 Q52EG 1 3 1
4 Q52EG 1 4 1
5 QQ8Q4 0 5 0
6 QQ8Q4 0 6 0
7 QQ8Q4 1 7 0
8 QQ8Q4 1 8 1
9 QVIPW 1 9 0

Я делаю это, используя итеративный подход, подобный этому:

 previous_present = {}
has_prv_history = []
for index, value in id_df.iterrows():
    my_id = value["ids"]
    ftest_mentioned = value["ftest"]
    previous_flag = 0
    if my_id in previous_present.keys():
        previous_flag = 1
    elif (ftest_mentioned == 1):
        previous_present[my_id] = 1
    has_prv_history.append(previous_flag)
id_df["has_hist"] = has_prv_history
 

Можно ли этот код векторизовать без использования apply ?

Ответ №1:

Две ключевые функции для такого рода задач-это shift и ffill , применяемые для каждой группы. Для этого конкретного вопроса:

 df2["has_hist"] = df.groupby("ids").ftest.shift().where(lambda s: s.eq(1))
df2["has_hist"] = df2.groupby("ids").has_hist.ffill().fillna(0).astype("int32")
 

Вот вариант с transform , который, однако, часто медленнее, чем «чистые» операции с Пандами, по моему опыту:

 df2 = (
    df
    .groupby("ids")
    .ftest.transform(
        lambda s: (
            s
            .shift()
            .where(lambda t: t.eq(1))
            .ffill()
            .fillna(0)
            .astype("int32")
        )
    )
)