У меня есть фрейм данных, содержащий значения с плавающей запятой

my_df = pd.DataFrame([1,2,1,4,3,2,5,4,7])

Я пытаюсь найти для каждого номера, когда (сколько индексов нужно переместить вперед ), пока я не найду следующее число больше текущего числа, если нет большего числа, я отмечу его какое-то значение (например, 999999).

Таким образом, для приведенного выше примера правильный ответ должен быть

result = [1,2,1,3,2,1,2,1,999999]

В настоящее время я решил это с помощью очень медленного двойного цикла с itertuples (что означает O (n ^ 2))

Есть ли способ сделать это поумнее?

1
OopsUser 15 Окт 2019 в 10:49

1 ответ

Лучший ответ

Вот одно из основанных на использовании вещания вещаний:

a = my_df.squeeze().to_numpy() # my_df.squeeze().values for versions 0.24.0.<

diff_mat = a - a[:,None]
result = (np.triu(diff_mat)>0).argmax(1) - np.arange(diff_mat.shape[1])
result[result <= 0] = 99999

print(result)

array([    1,     2,     1,     3,     2,     1,     2,     1, 99999],
      dtype=int64)

Где diff_mat - матрица расстояний, и мы ищем значения от главной диагонали и далее, которые больше 0:

array([[ 0,  1,  0,  3,  2,  1,  4,  3,  6],
       [-1,  0, -1,  2,  1,  0,  3,  2,  5],
       [ 0,  1,  0,  3,  2,  1,  4,  3,  6],
       [-3, -2, -3,  0, -1, -2,  1,  0,  3],
       [-2, -1, -2,  1,  0, -1,  2,  1,  4],
       [-1,  0, -1,  2,  1,  0,  3,  2,  5],
       [-4, -3, -4, -1, -2, -3,  0, -1,  2],
       [-3, -2, -3,  0, -1, -2,  1,  0,  3],
       [-6, -5, -6, -3, -4, -5, -2, -3,  0]], dtype=int64)

У нас есть np.triu для этого:

np.triu(diff_mat)

array([[ 0,  1,  0,  3,  2,  1,  4,  3,  6],
       [ 0,  0, -1,  2,  1,  0,  3,  2,  5],
       [ 0,  0,  0,  3,  2,  1,  4,  3,  6],
       [ 0,  0,  0,  0, -1, -2,  1,  0,  3],
       [ 0,  0,  0,  0,  0, -1,  2,  1,  4],
       [ 0,  0,  0,  0,  0,  0,  3,  2,  5],
       [ 0,  0,  0,  0,  0,  0,  0, -1,  2],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  3],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0]], dtype=int64)

И проверив, что больше 0, и взяв argmax логического ndarray, мы найдем первое значение больше 0 в каждой строке:

(np.triu(diff_mat)>0).argmax(1)
array([1, 3, 3, 6, 6, 6, 8, 8, 0], dtype=int64)

Нам нужно только вычесть соответствующее смещение от главной диагонали к началу

1
yatu 15 Окт 2019 в 08:29