Панды: количество событий с момента последней победы на ID - PullRequest
0 голосов
/ 12 сентября 2018

Это пример моего набора данных об онлайн-играх. У нас есть идентификатор сеанса, который квалифицирует ставку, дата, когда произошла ставка, и результат ставки (win-draw-lost):

e = {'session': ['1', '3', '1', '1', '3', '1', '2', '2', '1', '3',  '3', '3', '3', '3',  '2', '3', '3'],
    'date': ['2018-01-01 00:17:05', '2018-01-01 00:30:35', '2018-01-01 00:19:05', '2018-01-03 00:55:22',
             '2018-01-01 00:21:07', '2018-01-01 00:22:09', '2018-02-01 00:35:22', 
             '2018-01-01 00:22:17',  '2018-01-01 00:25:11', '2018-01-01 00:27:28', '2018-01-01 00:29:29',
              '2018-01-01 00:25:09',   '2018-01-01 00:17:01', '2018-02-01 00:31:16',  
             '2018-02-01 00:38:20', '2018-02-01 00:55:15',  '2018-02-01 00:38:16'], 
    'status': ['win', 'loss', 'loss', 'draw', 'loss', 'win', 'loss', 'loss', 'win', 'draw', 'loss', 'loss', 'loss', 
               'win', 'draw', 'loss', 'loss']}

#create dataframe
df2 = pd.DataFrame(data=e)
#sort it by session and date
df2 = df2.sort_values(['session', 'date']).reset_index(drop=True)
df.head()

 session      date           status
0   1   2018-01-01 00:17:05   win
1   1   2018-01-01 00:19:05   loss
2   1   2018-01-01 00:22:09   win
3   1   2018-01-01 00:25:11   win
4   1   2018-01-03 00:55:22   draw

Моя цель - подсчитать для каждой сессии максимальное количество сыгранных игр без выигрыша. Это то, что я сделал, следуя совету этого ТАК сообщения :

1. Сначала я создал столбец, в котором win = 1 , а остальные значения = 0

.
m = {'win':1, 'loss':0, 'draw':0}
df2['status_num'] = df2.status.map(m)

session      date            status   status_num
0   1   2018-01-01 00:17:05  win        1
1   1   2018-01-01 00:19:05  loss       0
2   1   2018-01-01 00:22:09  win        1
3   1   2018-01-01 00:25:11  win        1
4   1   2018-01-03 00:55:22  draw       0

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

#create list of sessions
plist = list(df2.session.unique())

final = pd.DataFrame()
for i in plist:
    #slice the dataset by session
    sess = df2.loc[df2['session'] == i]
    #calculate the last win occurrence
    sess['Last_win']= sess.groupby(sess.status_num.cumsum()).cumcount()
    #append the result
    final = final.append(sess)

final
session date                status status_num   Last_win
0   1   2018-01-01 00:17:05  win        1         0
1   1   2018-01-01 00:19:05  loss       0         1
2   1   2018-01-01 00:22:09  win        1         0
3   1   2018-01-01 00:25:11  win        1         0
4   1   2018-01-03 00:55:22  draw       0         1

3. Наконец, я группируюсь, чтобы получить максимальную последовательность без какого-либо выигрышного события за сессию :

last_win = final.groupby('session')['Last_win'].max().reset_index()
last_win
session Last_win
0   1     1
1   2     2
2   3     5

Код делает то, что мне было нужно, НО он не очень производительный, и, поскольку у меня большой набор данных, я хотел бы найти лучшее решение с точки зрения времени выполнения. я совершенно уверен, что узким местом является цикл for, и тот факт, что для каждой итерации я делаю групповую работу, но на самом деле я не могу придумать другой путь. Я также попробовал подход, предложенный здесь , но мне не интересны дни.

1 Ответ

0 голосов
/ 13 сентября 2018

Сначала я бы определил функцию для расчета разницы для одного сеанса следующим образом: ПРИМЕЧАНИЕ: предполагается, что вы отсортировали кадр данных так, как вы это сделали.

def events_to_last_win(df):

    vec = []
    counter=0
    for i in df.index:

        if df.loc[i,'status'] == 'win':
            counter = 0
        else: 
            counter += 1


        vec.append(counter)
    return vec

Затем выполните начальную настройку:

import pandas as pd
e = {'session': ['1', '3', '1', '1', '3', '1', '2', '2', '1', '3',  '3', '3', '3', '3',  '2', '3', '3'],
    'date': ['2018-01-01 00:17:05', '2018-01-01 00:30:35', '2018-01-01 00:19:05', '2018-01-03 00:55:22',
             '2018-01-01 00:21:07', '2018-01-01 00:22:09', '2018-02-01 00:35:22', 
             '2018-01-01 00:22:17',  '2018-01-01 00:25:11', '2018-01-01 00:27:28', '2018-01-01 00:29:29',
              '2018-01-01 00:25:09',   '2018-01-01 00:17:01', '2018-02-01 00:31:16',  
             '2018-02-01 00:38:20', '2018-02-01 00:55:15',  '2018-02-01 00:38:16'], 
    'status': ['win', 'loss', 'loss', 'draw', 'loss', 'win', 'loss', 'loss', 'win', 'draw', 'loss', 'loss', 'loss', 
               'win', 'draw', 'loss', 'loss']}


df = pd.DataFrame(data=e)
#sort it by session and date
df = df.sort_values(['session', 'date']).reset_index(drop=True)

Затем мы можем присвоить столбцу Last_win фиктивное значение и обновить его по идентификатору сеанса, используя функцию, которую мы определили:

df['Last_win'] = 0
for session in df.session.unique()):
    df.loc[df.session == session,'Last_win'] = events_to_last_win( df[df.session == session])

df.groupby('session')['Last_win'].max().reset_index()

Среднее время выполнения этого метода более 1000 запусков на моей машине составляет 0,0153894310000004

По сравнению со средним значением для 1000 прогонов метода, указанного в вопросе: 0,19408468899999962

Примечание. Я не проверял значения, полученные с помощью этого подхода, но это должно наметить гораздо более быстрый способ решения проблемы

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...