#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")
)
)
)