Pandas dataframe получает значение последнего ненулевого столбца - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть кадр данных pandas, который содержит 3 столбца, каждый из которых содержит сайт, который пользователь посетил во время сеанса.

В некоторых случаях пользователь не посещал 3 сайта за один сеанс. Это обозначено 0, что означает, что ни один сайт не был посещен.

import pandas as pd

df = pd.DataFrame(data=[[5, 8, 1],[8,0,0],[1,17,0]], 
                  columns=['site1', 'site2', 'site3'])
print(df)

   site1  site2  site3
0      5      8      1
1      8      0      0
2      1     17      0

В приведенном выше примере пользователь 0 посетил сайты 5, 8 и 1. Пользователь 1 посетил только сайт 8, а пользователь 2 посетил сайты 1 и 17.

Я хотел бы создать новый столбец last_site, который показывает последний сайт, посещенный пользователем в этом сеансе.

Результат, который я хочу получить, таков:

   site1  site2  site3  last_site
0      5      8      1          1
1      8      0      0          8
2      1     17      0         17

Как я могу сделать это кратко, используя панд?

Ответы [ 3 ]

0 голосов
/ 03 ноября 2018

Код:

df['last_site'] = df.apply(lambda x: x.iloc[x.nonzero()].iloc[-1], axis=1)

Выход:

   site1  site2  site3  last_site
0      5      8      1          1
1      8      0      0          8
2      1     17      0         17
0 голосов
/ 03 ноября 2018

mask + ffill

Раствор "чистых панд":

df['last'] = df.mask(df.eq(0)).ffill(1).iloc[:, -1].astype(int)

numba

Для повышения эффективности при большом количестве строк / столбцов может помочь numba. Чтобы понять, почему это работает лучше, чем argmax, см. Эффективно вернуть индекс первого значения, удовлетворяющего условию в массиве .

from numba import njit

@njit
def get_last_val(A):
    m, n = A.shape
    res = A[:, -1]
    for i in range(m):
        for j in range(n):
            if A[i, j] == 0:
                res[i] = A[i, max(0, j-1)]
                break
    return res

df['last'] = get_last_val(df.values)
0 голосов
/ 03 ноября 2018

Использовать прямое заполнение значений misisng, созданных путем замены значений 0, а затем выбрать последний столбец на iloc:

df['last'] = df.replace(0, np.nan).ffill(axis=1).iloc[:, -1].astype(int)
print (df)
   site1  site2  site3  last
0      5      8      1     1
1      8      0      0     8
2      1     17      0    17

Если важна производительность, используйте numpy:

a = df.values
m = a != 0

df['last'] = a[np.arange(m.shape[0]), m.shape[1]-m[:,::-1].argmax(1)-1]
print (df)
   site1  site2  site3  last
0      5      8      1     1
1      8      0      0     8
2      1     17      0    17
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...