np.where индекс больше определенного значения - PullRequest
0 голосов
/ 29 июня 2018

Я предполагал, что это будет довольно просто, но, видимо, я что-то здесь упускаю.

Я хочу иметь возможность использовать np.where с df.groupby('Name').apply() для создания нового столбца в df (назовите его 'New'), где значения столбца 1, если индексы соответствующих группа (индексы, соответствующие исходному df) больше или равна (>=) определенного значения, в противном случае 0.

Для фона я группирую df по столбцу 'Name', и у меня есть dict(), который содержит соответствующее значение для использования для каждого имени из groupby(). Я надеюсь, что это понятно, я могу дать дополнительные разъяснения, если это необходимо.

Вот то, что я имею до сих пор, данный пример df:

df = pd.DataFrame([['William', 1, 0, 0, 0, 1],['James', 0, 1, 1, 1, 1],['James', 1, 0, 0, 0, 0],
                ['James', 1, 0, 1, 1, 0],['William', 0, 1, 1, 0, 1],['William', 0, 0, 0, 0, 0],
                ['William', 1, 0, 1, 1, 0],['James', 0, 1, 1, 0, 1],['James', 0, 0, 0, 0, 0]],
                columns=['Name','x1','x2','x3','x4','Interest'])

       Name  x1  x2  x3  x4  Interest
0  William   1   0   0   0         1
1    James   0   1   1   1         1
2    James   1   0   0   0         0
3    James   1   0   1   1         0
4  William   0   1   1   0         1
5  William   0   0   0   0         0
6  William   1   0   1   1         0
7    James   0   1   1   0         1
8    James   0   0   0   0         0

Затем я нахожу последнюю строку в df для каждой группы, где столбец 'Interest' имеет 1, используя:

mydict = df[df['Interest']==1].groupby('Name').apply(lambda x: x.index[-1]).to_dict()

{'James': 7, 'William': 4}

Примечание. Это упрощенный пример. Для моего реального приложения я вытягиваю указатель с 3-й по последнюю строку (т. Е. .apply(lambda x: x.index[-3]).to_dict()), однако в следующей части находится корень моего вопроса.

Теперь я хочу создать новый столбец 'Name', где значение равно 1, если индекс строки равен >=, значение в mydict для этой группы, иначе 0. Я попробовал несколько вещей:

for key, val in mydict.items():
    df['New'] = np.where((df['Name']==key) & (df.index>=val), 1, 0)

Это, очевидно, переопределит все, что сделано для 'James' и просто вернет правильный столбец для 'William'. Как я могу эффективно сделать это?

Если быть точным, вот мой ожидаемый результат:

      Name  x1  x2  x3  x4  Interest  New
0  William   1   0   0   0         1    0
1    James   0   1   1   1         1    0
2    James   1   0   0   0         0    0
3    James   1   0   1   1         0    0
4  William   0   1   1   0         1    1
5  William   0   0   0   0         0    1
6  William   1   0   1   1         0    1
7    James   0   1   1   0         1    1
8    James   0   0   0   0         0    1

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Использование map

df.assign(New=(df.index >= df.Name.map(mydict)).astype(int))

      Name  x1  x2  x3  x4  Interest  New
0  William   1   0   0   0         1    0
1    James   0   1   1   1         1    0
2    James   1   0   0   0         0    0
3    James   1   0   1   1         0    0
4  William   0   1   1   0         1    1
5  William   0   0   0   0         0    1
6  William   1   0   1   1         0    1
7    James   0   1   1   0         1    1
8    James   0   0   0   0         0    1
0 голосов
/ 29 июня 2018

Используйте списочное понимание для всех масок, а затем уменьшите их до одной, в конце преобразуйте их в целое число - True s равны 1 s:

m = [((df['Name']==key) & (df.index>=val)) for key, val in mydict.items()]
print (m)
[0    False
1    False
2    False
3    False
4    False
5    False
6    False
7     True
8     True
Name: Name, dtype: bool, 0    False
1    False
2    False
3    False
4     True
5     True
6     True
7    False
8    False
Name: Name, dtype: bool]

df['New'] = np.logical_or.reduce(m).astype(int)
print (df)
      Name  x1  x2  x3  x4  Interest  New
0  William   1   0   0   0         1    0
1    James   0   1   1   1         1    0
2    James   1   0   0   0         0    0
3    James   1   0   1   1         0    0
4  William   0   1   1   0         1    1
5  William   0   0   0   0         0    1
6  William   1   0   1   1         0    1
7    James   0   1   1   0         1    1
8    James   0   0   0   0         0    1

EDIT:

Другое решение этой проблемы:

df = pd.concat([df] * 2, ignore_index=True)

Получить индекс первого истинного значения для условия - посчитать 3-е значение со спины

idx = df[df['Interest']==1].groupby('Name').cumcount(ascending=False).eq(2).idxmax()

Установить значения от idx до конца 1:

df['New'] = 0
df.loc[idx:, 'New'] = 1
print (df)
       Name  x1  x2  x3  x4  Interest  New
0   William   1   0   0   0         1    0
1     James   0   1   1   1         1    0
2     James   1   0   0   0         0    0
3     James   1   0   1   1         0    0
4   William   0   1   1   0         1    1
5   William   0   0   0   0         0    1
6   William   1   0   1   1         0    1
7     James   0   1   1   0         1    1
8     James   0   0   0   0         0    1
9   William   1   0   0   0         1    1
10    James   0   1   1   1         1    1
11    James   1   0   0   0         0    1
12    James   1   0   1   1         0    1
13  William   0   1   1   0         1    1
14  William   0   0   0   0         0    1
15  William   1   0   1   1         0    1
16    James   0   1   1   0         1    1
17    James   0   0   0   0         0    1

Detail

print (df[df['Interest']==1].groupby('Name').cumcount(ascending=False))
0     3
1     3
4     2
7     2
9     1
10    1
13    0
16    0
dtype: int64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...