Удалите строки заголовка и хвоста с нулевым значением из DataFrame - PullRequest
0 голосов
/ 12 сентября 2018

У меня есть коллекция DataFrames с нулевыми значениями заголовка и хвоста. Я хотел бы отбросить эти строки с нулевым значением и сохранить диапазон между ними.

Например, учитывая этот DataFrame:

   x
0  0
1  0
2  1 
3  0
4  3
5  1
6  0
7  0

Я хотел бы функцию, которая возвращает это:

   x
2  1 
3  0
4  3
5  1

Обратите внимание, что нулевое значение в строке 3 не было потеряно. Я не хочу удалять все нули, только голову и хвост. Как это можно сделать с помощью панд?

Ответы [ 6 ]

0 голосов
/ 12 сентября 2018
d={'x':[0,0,1,2,1,0,0,4,4,0,0]}
df=pd.DataFrame(d)

Удалить нули хвоста:

i=len(df)-1
x=df['x'][i]

while x==0:
    i-=1
    x=df['x'][i]
df=df[0:i+1] 

Удалить нули головы:

while x==0:
    del df['x'][i]
    i-=1
    x=df['x'][i]
df=df[i:] 
0 голосов
/ 12 сентября 2018

Inspire by mad_

df.loc[df.x.mask(df.x==0).first_valid_index():df.x.mask(df.x==0).last_valid_index()]
Out[39]: 
   x
2  1
3  0
4  3
5  1
0 голосов
/ 12 сентября 2018

Я также выставлю свою лошадь в этой гонке.

Cumum вперед, cumsum назад, примите минимальное значение, если равно нулю, сбросьте.

df[np.minimum(df['x'].cumsum(), df['x'][::-1].cumsum()[::-1]).ne(0)]

Вывод:

   x
2  1
3  0
4  3
5  1
0 голосов
/ 12 сентября 2018

Для больших массивов с несколькими нулями ручная итерация будет более эффективной, чем логическое индексирование.Например, через выражение генератора с next и enumerate:

start = next(idx for idx, val in enumerate(df['x']) if val != 0)
end = -next(idx for idx, val in enumerate(df['x'].iloc[::-1]) if val != 0)

res = df['x'].iloc[start:end]

2    1
3    0
4    3
5    1
Name: x, dtype: int64
0 голосов
/ 12 сентября 2018

Это также может быть полезно. nonzero даст индексы ненулевых элементов в ряду. Доступ к первому и последнему индексу кортежа приведет к ожидаемому результату

import pandas as pd
df2=pd.DataFrame({'cols':[0,0,1,0,3,1,0,0]})
non_zero_index = df2.cols.nonzero()[0]
start, end = non_zero_index[0],non_zero_index[-1]
df2.loc[start:end]
    cols
2   1
3   0
4   3
5   1
0 голосов
/ 12 сентября 2018

Использование:

df = df[df['x'].cumsum().mul(df['x'].iloc[::-1].cumsum()).ne(0)]
print (df)
   x
2  1
3  0
4  3
5  1

Объяснение :

Получить cumsum столбца:

print (df['x'].cumsum())
0    0
1    0
2    1
3    1
4    4
5    5
6    5
7    5
Name: x, dtype: int64

Инвертировать столбец и снова cumsum:

print (df['x'].iloc[::-1].cumsum())
7    0
6    0
5    1
4    4
3    4
2    5
1    5
0    5
Name: x, dtype: int64

Умножить на Series.mul:

print (df['x'].cumsum().mul(df['x'].iloc[::-1].cumsum()))
0     0
1     0
2     5
3     4
4    16
5     5
6     0
7     0
Name: x, dtype: int64

И проверить, не равен ли ne (!=) из 0:

print (df['x'].cumsum().mul(df['x'].iloc[::-1].cumsum()).ne(0))
0    False
1    False
2     True
3     True
4     True
5     True
6    False
7    False
Name: x, dtype: bool

Последний фильтр по boolean indexing.

Спасибо @Wen за другое решение:

df[(df.x.eq(0).cumprod().eq(0))&(df.x[::-1].eq(0).cumprod().eq(0))]  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...