Использование:
m = df['col1'].ne(0)
s = m.cumsum() * (~m)
df = df[s.groupby(s).transform('size').lt(2) | m]
Или:
df = df[s.map(s.value_counts()).lt(2) | m]
print (df)
col1 col2 col3
0 1 2 3
3 2 7 8
4 0 1 2
5 4 4 4
9 4 6 2
Объяснение
Первое сравнение для не равных 0
по Series.ne
:
print (df['col1'].ne(0))
0 True
1 False
2 False
3 True
4 False
5 True
6 False
7 False
8 False
9 True
Name: col1, dtype: bool
Затем используйте cumsum
для групп - значения с 0
имеют одинаковые группы:
print (m.cumsum())
0 1
1 1
2 1
3 2
4 2
5 3
6 3
7 3
8 3
9 4
Name: col1, dtype: int32
Умножается на инвертированную логическую маску для удаления не 0
значений:
print (m.cumsum() * (~m))
0 0
1 1
2 1
3 0
4 2
5 0
6 3
7 3
8 3
9 0
Name: col1, dtype: int32
Затем подсчитайте количество групп по GroupBy.transform
:
print (s.groupby(s).transform('size'))
0 4
1 2
2 2
3 4
4 1
5 4
6 3
7 3
8 3
9 4
Name: col1, dtype: int64
И сравните по lt
<
:
print (s.groupby(s).transform('size').lt(2))
0 False
1 False
2 False
3 False
4 True
5 False
6 False
7 False
8 False
9 False
Name: col1, dtype: bool
Последняя цепочка по оригинальной маске m
по |
для побитовой OR
:
print (s.groupby(s).transform('size').lt(2) | m)
0 True
1 False
2 False
3 True
4 True
5 True
6 False
7 False
8 False
9 True
Name: col1, dtype: bool
И последний фильтр по boolean indexing
:
print (df[s.groupby(s).transform('size').lt(2) | m])
col1 col2 col3
0 1 2 3
3 2 7 8
4 0 1 2
5 4 4 4
9 4 6 2