Найти последний элемент строки датафрейма pandas, неравный нулю
Необходимо найти последний элемента на каждой строке массива не равный нулю. Решение для списка довольно простое:
b = 0
c = 0
list_a = [0,1,2,5,0,0]
for index in range(0, len(list_a)):
if list_a[index] != 0:
b = index
c = list_a[index]
print('индекс', b, 'значение', c)
# условие для пандас
import pandas as pd
data = [[1,5,0],
[1,0,0],
[5,9,7],
[0,0,0]]
columns = ['n1','n2', 'n3']
df = pd.DataFrame(data = data, columns = columns)
# ожидаемое решение
import pandas as pd
data = [[1,5,0,5,'n2'],
[1,0,0,1,'n1'],
[5,9,7,7,'n3'],
[0,0,0,0, None]]
columns = ['n1','n2', 'n3','last','last_head']
df = pd.DataFrame(data = data, columns = columns)
Ответы (3 шт):
data = [[1, 5, 0],
[1, 0, 0],
[5, 9, 7],
[0, 0, 0]]
columns = ['n1', 'n2', 'n3']
df = pd.DataFrame(data=data, columns=columns)
def find_last(row):
last_value = row[row != 0].iloc[-1] if (row != 0).any() else 0
last_head = row.index[row == last_value][-1] if last_value != 0 else None
return pd.Series([last_value, last_head], index=['last', 'last_head'])
df[['last', 'last_head']] = df.apply(find_last, axis=1)
print(df)
- Создается набор данных (data) и столбцы (columns).
- Создается DataFrame (df) с помощью библиотеки pandas из набора данных и столбцов.
- Создается функция findlast, которая принимает строку (row) и находит последний ненулевой элемент в этой строке и его индекс.
- Применяется функция findlast к каждой строке DataFrame (df) с помощью метода apply и сохраняются новые столбцы 'last' и 'lasthead', содержащие последний ненулевой элемент и его индекс соответственно.
- Выводится новый DataFrame (df) с добавленными столбцами 'last' и 'lasthead'.
Более подробно о всех методах которые использовались можете прочитать в документации pandas
Сначала разворачиваем фрейм в один Series с помощью stack(). Индексы (номера) строк и названия колонок становятся мультииндексом. Затем заменяем все нули на None и удаляем через dropna(). Удаляем дубликаты по номерам строк, оставляя последнее вхождение. Возвращаем номера строк в индекс, чтобы "состыковать" результат с исходным фреймом. Создаем две новые колонки и помещаем результат. При необходимости можно заменить None в колонке last на 0, но, по-моему, лучше так не делать - см. комментарий в коде.
df[['last', 'last_head']] = df.stack().replace(0, None).dropna().reset_index().drop_duplicates('level_0', keep='last').set_index('level_0')[[0, 'level_1']]
df['last'] = df['last'].fillna(0) # можно оставить, но концептуальнее - убрать. Ведь если "найти последний элемент на каждой строке массива, не равный нулю", а все нули - то д.б. не 0, а None
print(df)
n1 n2 n3 last last_head
0 1 5 0 5 n2
1 1 0 0 1 n1
2 5 9 7 7 n3
3 0 0 0 0 NaN
Вариант покороче с той же логикой, где drop_duplicates('level_0', keep='last').set_index('level_0') заменено на groupby(level=0).last()
df[['last', 'last_head']] = df.stack().replace(0, None).dropna().reset_index(level=1).groupby(level=0).last()[[0, 'level_1']]
Наглядная схема преобразований:
Можно сделать так:
df["last_head"] = df.apply(lambda x: x[x.ne(0)].index[-1] if len(x[x.ne(0)]) else None, axis=1)
df["head"]=df[df["last_head"].notna()].apply(lambda x:x.loc[x["last_head"]], axis=1)
df:
n1 n2 n3 last_head head
0 1 5 0 n2 5.0
1 1 0 0 n1 1.0
2 5 9 7 n3 7.0
3 0 0 0 None NaN
