Чистая нарезка Numpy и прочее
Смысл этих усилий в том, чтобы ОП попросил скорость. Это должно помочь. Если у вас есть доступ к библиотеке JIT, такой как numba
, вы должны использовать ее и просто зацикливаться на каждой строке.
sd = startday.start.values
ed = endday.end.values
dr = ed - sd + 1
i = np.arange(len(df)).repeat(dr)
j = np.concatenate([np.arange(s - 1, e) for s, e in zip(sd, ed)])
v = df.values
mx = np.empty(len(v), dtype=v.dtype)
mx.fill(v.min())
np.maximum.at(mx, i, v[i, j])
b = np.ones((v.shape[0], v.shape[1] + 2), bool)
b[i, j + 1] = (v[i, j] != mx[i]) | (mx[i] == 0)
x, y = np.where(b)
y_ = np.diff(y)
mask = y_ > 0
y__ = y_[mask]
x__ = x[1:][mask]
c = np.empty(len(v), int)
c.fill(y__.min())
np.maximum.at(c, x__, y__)
c - 1
array([2, 1, 3, 6, 1, 3, 0, 3, 1, 2])
Объяснение
Я оставлю очевидное в покое.
Это число дней в каждом интервале
dr = ed - sd + 1
i
- сглаженные индексы соответствующих строк для соответствующих сглаженных индексов столбцов в j
i = np.arange(len(df)).repeat(dr)
j = np.concatenate([np.arange(s - 1, e) for s, e in zip(sd, ed)])
mx
будет максимальным значением для каждого интервала.
b
будет логическим массивом с шириной на 2 столбца больше, чем v
. Для этого случая это выглядит так:
# Buffer Buffer
# /--\ /--\
array([[ True, True, True, False, False, True, False, True, True],
[ True, True, True, False, True, True, True, True, True],
[ True, False, False, False, True, False, False, True, True],
[ True, True, False, False, False, False, False, False, True],
[ True, True, False, True, True, True, False, True, True],
[ True, False, False, True, True, False, False, False, True],
[ True, False, False, False, False, False, False, False, True],
[ True, True, True, True, False, False, False, True, True],
[ True, True, True, False, True, True, True, False, True],
[ True, True, False, False, True, True, True, True, True]])
Причина появления столбцов буфера в том, что я могу вычислить разницу позиций после использования np.where
Теперь я заполняю b
, где значения v
не равны максимальным значениям в mx
# not equal to max is equal to zero
b[i, j + 1] = (v[i, j] != mx[i]) | (mx[i] == 0)
Затем я нахожу, где находятся эти позиции y
.
Взяв diff
, я нахожу количество позиций от одного экземпляра, не равного max, до следующей позиции, не равной max. Это всегда будет на единицу больше, чем искомое число, но мы исправим это позже.
Кроме того, diff
уменьшит длину на единицу, но на самом деле есть куча вещей, которые нам не нужны, потому что мне не нужно брать разницу из одного ряда относительно предыдущего ряда. К счастью, я могу избавиться от всех нулевых или отрицательных различий, потому что они не имеют смысла.
Я использую np.maximum.at
(снова), но на этот раз для различий, чтобы найти наибольшую разницу, и это будет наибольшая длина последовательных максимальных значений для каждой строки.
Имейте в виду, что это на самом деле больше, чем
Уф. Я устал печатать ...