Найти последний элемент строки датафрейма 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 шт):

Автор решения: Nikolai_Narushev
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)
  1. Создается набор данных (data) и столбцы (columns).
  2. Создается DataFrame (df) с помощью библиотеки pandas из набора данных и столбцов.
  3. Создается функция findlast, которая принимает строку (row) и находит последний ненулевой элемент в этой строке и его индекс.
  4. Применяется функция findlast к каждой строке DataFrame (df) с помощью метода apply и сохраняются новые столбцы 'last' и 'lasthead', содержащие последний ненулевой элемент и его индекс соответственно.
  5. Выводится новый 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']]

Наглядная схема преобразований:


введите сюда описание изображения

→ Ссылка
Автор решения: strawdog

Можно сделать так:

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
→ Ссылка