Вычислить выигрышную серию с пандами - PullRequest
0 голосов
/ 24 октября 2018

Я думал, что знаю, как это сделать, но я дергаю себя за волосы.Я пытаюсь использовать функцию для создания нового столбца.Функция просматривает значение столбца win в текущей строке и должна сравнить его с предыдущим числом в столбце win, как указано ниже в операторах if.Столбец выигрыша всегда будет равен 0 или 1.

import pandas as pd
data = pd.DataFrame({'win': [0, 0, 1, 1, 1, 0, 1]})
print (data)

   win
0    0
1    0
2    1
3    1
4    1
5    0
6    1

def streak(row):
    win_current_row = row['win']
    win_row_above = row['win'].shift(-1)
    streak_row_above = row['streak'].shift(-1)

    if (win_row_above == 0) & (win_current_row == 0):
        return 0
    elif (win_row_above == 0) & (win_current_row ==1):
        return 1
    elif (win_row_above ==1) & (win_current_row == 1):
        return streak_row_above + 1
    else:
        return 0

data['streak'] = data.apply(streak, axis=1)

Все это заканчивается этой ошибкой:

AttributeError: ("'numpy.int64' object has no attribute 'shift'", 'occurred at index 0')

В других примерах я вижу функции, которые ссылаются на df['column'].shift(1), поэтомуЯ смущен, почему я не могу сделать это в этом случае.

Вывод, который я тоже пытаюсь получить, таков:

result = pd.DataFrame({'win': [0, 0, 1, 1, 1, 0, 1], 'streak': ['NaN', 0 , 1, 2, 3, 0, 1]})
print(result)

   win streak
0    0    NaN
1    0      0 
2    1      1
3    1      2
4    1      3
5    0      0
6    1      1

Спасибо за помощь, чтобы освободить меня.

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Довольно распространенный прием при использовании pandas - группировка по последовательным значениям.Этот трюк хорошо описан здесь .

Чтобы решить вашу конкретную проблему, мы хотим groupby последовательных значений, а затем использовать cumsum, что означает, что группы потерь (группы0) будет иметь совокупную сумму 0, в то время как группы побед (или группы 1) будут отслеживать выигрышные серии.

grouper = (df.win != df.win.shift()).cumsum()
df['streak'] = df.groupby(grouper).cumsum()

   win  streak
0    0       0
1    0       0
2    1       1
3    1       2
4    1       3
5    0       0
6    1       1

Для объяснения, вот наш grouper Series, который позволяет нам группировать по непрерывным областям 1 и 0:

print(grouper)

0    1
1    1
2    2
3    2
4    2
5    3
6    4
Name: win, dtype: int64
0 голосов
/ 24 октября 2018

Причина, по которой вы получаете эту ошибку, заключается в том, что shift () - это метод панд.Ваш код пытался получить значение в строке (row ['win']), которое имеет значение numpy.int64.Таким образом, вы пытаетесь выполнить shift () для numpy.int64.Для этого df ['column']. Shift (1) берется столбец с датой, который также является кадром данных, и смещает этот столбец на 1.

Чтобы проверить это самостоятельно, попробуйте print (type (data [')win '])) и print (type (row [' win '])) и print (type (row))

Это сообщит вам тип данных.

также вы получитеошибка, когда вы попадаете на
streak_row_above = row ['streak']. shift (-1)

, потому что вы ссылаетесь на строку ['streak'] до ее создания.

0 голосов
/ 24 октября 2018

Давайте попробуем groupby и cumcount:

m = df.win.astype(bool)
df['streak'] = (
    m.groupby([m, (~m).cumsum().where(m)]).cumcount().add(1).mul(m))

df
   win  streak
0    0       0
1    0       0
2    1       1
3    1       2
4    1       3
5    0       0
6    1       1

Как это работает

Используя df.win.astype(bool), конвертируем df['win'] вего логический эквивалент (1 = True, 0 = False).

Далее,

(~m).cumsum().where(m)

0    NaN
1    NaN
2    2.0
3    2.0
4    2.0
5    NaN
6    3.0
Name: win, dtype: float64

Представляет все смежные единицы с уникальным номером, причем 0 маскируются как NaN.

Теперь используйте groupby и cumcount, чтобы назначить каждой строке в группе монотонно увеличивающееся число.

m.groupby([m, (~m).cumsum().where(m)]).cumcount()

0    0
1    1
2    0
3    1
4    2
5    2
6    0
dtype: int64

Это то, что мы хотим, но вы можете видеть, что это1) с нуля и 2) также присваивает значения 0 (без выигрыша).Мы можем использовать m, чтобы замаскировать его (x раз 1 (= True) равно x, а любое 0 (= False) равно 0).

m.groupby([m, (~m).cumsum().where(m)]).cumcount().add(1).mul(m)

0    0
1    0
2    1
3    2
4    3
5    0
6    1
dtype: int64

Назначить это обратно на место.

...