Удалить строки идентификатора после определенного значения столбца в Pandas - PullRequest
5 голосов
/ 06 апреля 2019

У меня есть такой набор данных:

Id   Status

1     0
1     0
1     0
1     0
1     1
2     0
1     0
2     0
3     0
3     0

Я хочу удалить все строки идентификатора после того, как его статус станет 1, т.е. мой новый набор данных будет:

Id   Status

1     0
1     0
1     0
1     0
1     1
2     0
2     0
3     0
3     0

i.e.

1     0   --> gets removed since this row appears after id 1 already had a status of 1

Какреализовать его эффективно, так как у меня очень большой (200 ГБ +) набор данных.

Спасибо за вашу помощь.

Ответы [ 3 ]

2 голосов
/ 06 апреля 2019

Вот идея;

Вы можете создать dict с первым индексом, где статус равен 1 для каждого идентификатора (при условии, что DataFrame отсортирован по ID):

d = df.loc[df["Status"]==1].drop_duplicates()
d = dict(zip(d["Id"], d.index))

ТогдаВы создаете столбец с первым status=1 для каждого идентификатора:

df["first"] = df["Id"].map(d)

Наконец, вы удаляете каждую строку, где индекс меньше, чем столбец first:

df = df.loc[df.index<df["first"]]
2 голосов
/ 06 апреля 2019

РЕДАКТИРОВАТЬ : Пересматривая этот вопрос через месяц, на самом деле есть гораздо более простой способ с groupby и cumsum: просто сгруппировать по Id и взять cumsum из Status затем сбросьте значения, где cumsum больше 0:

df[df.groupby('Id')['Status'].cumsum() < 1]

Лучший способ, который я нашел, - это найти индекс первой 1 и разделить каждую группу таким образом. В случае отсутствия 1, верните группу без изменений:

def remove(series):
    indexless = series.reset_index(drop=True)
    ones = indexless[indexless['Status'] == 1]
    if len(ones) > 0:
        return indexless.iloc[:ones.index[0] + 1]

    else:
        return indexless

df.groupby('Id').apply(remove).reset_index(drop=True)

Выход:

   Id  Status
0   1       0
1   1       0
2   1       0
3   1       0
4   1       1
5   2       0
6   2       0
7   3       0
8   3       0
1 голос
/ 06 апреля 2019

Используйте groupby с cumsum, чтобы найти статус 1.

res = df.groupby('Id', group_keys=False).apply(lambda x: x[x.Status.cumsum() > 0])
res

    Id  Status
4   1   1
6   1   0

Исключить индекс, который Status==0.

not_select_id = res[res.Status==0].index

df[~df.index.isin(not_select_id)]

Id  Status
0   1   0
1   1   0
2   1   0
3   1   0
4   1   1
5   2   0
7   2   0
8   3   0
9   3   0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...