Как векторизовать поиск значений столбцов в pandas dataframe - PullRequest
4 голосов
/ 11 мая 2019

Я хочу искать целевое значение в столбце данных pandas только в прямом направлении, и, если будет найдено большее значение, я хочу записать разницу индекса в качестве столбца результата. Мне удалось сделать это с двумя внутренними циклами for, но это было мучительно медленно.

Это то, чего я хочу достичь в упрощенном примере.

import pandas as pd

d = {
    'Value'  : [8,9,10,12,16,13,11,7,12,18],
    'Target' : [12,12,11,15,19,11,16,11,17,18]
    }
df = pd.DataFrame(data=d)


>>> df

   Target  Value
0      12      8
1      12      9
2      11     10
3      15     12
4      19     16
5      11     13
6      16     11
7      11      7
8      17     12
9      18     18

Нашим первым значением является 8, а нашим целевым значением для этого является 12. Мы смотрим в столбце Значение для значения, которое превышает это целевое значение. И мы находим его в строке 4 со значением 16. Я хочу записать разницу индексов, которая составляет 4-0 = 4.

Следующее значение равно 9, снова целевое значение равно 12. Мы смотрим в значения и снова находим строку-4 со значением 16. Теперь разница в индексе составляет 4-1 = 3

Позволяет перейти к строке 4. Мы начинаем искать целевое значение, начиная с индекса 5 и далее. Если значение не найдено, результат равен 0.

Это столбец результатов, к которому я хочу обратиться.

   Target  Value  Result
0      12      8       4
1      12      9       3
2      11     10       1
3      15     12       1
4      19     16       0
5      11     13       3
6      16     11       3
7      11      7       1
8      17     12       1
9      18     18       0

Можно ли это сделать без циклов?

Ответы [ 2 ]

4 голосов
/ 11 мая 2019

Использовать цифровую трансляцию для сравнения, установить верхнюю треугольную матрицу на False, получить первые True индексы на numpy.argmax, вычесть на arange и установить на 0 все негативы:

t = df['Target'].values[:, None]
v = df['Value'].values
m = v > t
m[np.tril_indices(m.shape[1])] = False
print (m)
[[False False False False  True  True False False False  True]
 [False False False False  True  True False False False  True]
 [False False False  True  True  True False False  True  True]
 [False False False False  True False False False False  True]
 [False False False False False False False False False False]
 [False False False False False False False False  True  True]
 [False False False False False False False False False  True]
 [False False False False False False False False  True  True]
 [False False False False False False False False False  True]
 [False False False False False False False False False False]]

a = np.argmax(m, axis=1) - np.arange(len(df))
print (a)
[ 4  3  1  1 -4  3  3  1  1 -9]

df['new'] = np.where(a > 0, a, 0)
print (df)
   Value  Target  new
0      8      12    4
1      9      12    3
2     10      11    1
3     12      15    1
4     16      19    0
5     13      11    3
6     11      16    3
7      7      11    1
8     12      17    1
9     18      18    0
1 голос
/ 11 мая 2019

Вы можете сократить его до одного для цикла. Используйте Series.first_valid_index () и логическое условие:

df['Result'] = 0
for i, target in enumerate(df.Target):
    val = df[(df.Value>target) & (df.index>i)]['Value'].first_valid_index()
    if val is not None:
        df.at[i, 'Result'] = val - i
df
   Value    Target  Result
0   8        12      4
1   9        12      3
2   10       11      1
3   12       15      1
4   16       19      0
5   13       11      3
6   11       16      3
7   7        11      1
8   12       17      1
9   18       18      0

Условия ищут каждую строку, где Value больше цели, но также только после индекса цели, и first_valid_index вернет первый индекс, где условие выполнено.

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