Это довольно интересная проблема, действительно. Я попытался решить его, разделив его на три части.
Группировка:
import numpy as np
import pandas as pd
x = np.array([2, 3, 4, 0, 0, 1, 1, 4, 6, 5, 8, 9, 9, 4, 2, 0, 3])
groups = pd.DataFrame(x).groupby([0]).indices
Таким образом, группы - это словарь {0: [3, 4, 15], 1: [5, 6], 2: [0, 14], 3: [1, 16], 4: [2, 7, 13], 5: [9], 6: [8], 8: [10], 9: [11, 12]}
, а его значения - numpy
массивы dtype=int64
.
Маскировка:
В этой части я перебираю несколько массивов масок x>=i
для каждого уникального значения i
в порядке убывания:
mask_array = np.zeros(x.size).astype(int)
for group in list(groups)[::-1]:
mask = mask_array[groups[group]] = 1
# print(group, ':', mask_array)
# output = find_slices(mask)
И эти маски выглядят так:
9 : [0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0]
8 : [0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0]
6 : [0 0 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0]
5 : [0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0]
4 : [0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0]
3 : [0 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 1]
2 : [1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 1]
1 : [1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 1]
0 : [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
Извлечение срезов из масок :
Я предполагаю построить некоторую функцию под названием find_slices
, которая извлекает позиции срезов из маскировать массивы (если вы раскомментируете это). Вот что я сделал:
def find_slices(m):
m1 = np.r_[0, m]
m2 = np.r_[m, 0]
starts, = np.where(~m1 & m2)
ends, = np.where(m1 & ~m2)
return np.c_[starts, ends - 1]
Например, позиции среза массива [0 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 1]
будут [[1, 2], [7, 13], [16, 16]]
. Обратите внимание, что это не стандартный способ возврата срезов, конечная позиция обычно увеличивается на 1.
Окончательный сценарий
В конце концов, для выполнения ожидаемый результат, вот как он выглядит в конце:
import numpy as np
import pandas as pd
x = np.array([2, 3, 4, 0, 0, 1, 1, 4, 6, 5, 8, 9, 9, 4, 2, 0, 3])
groups = pd.DataFrame(x).groupby([0]).indices
mask_array = np.zeros(x.size).astype(bool)
m = []
for group in list(groups)[::-1]:
mask_array[groups[group]] = True
s = find_slices(mask_array)
group_output = np.c_[np.repeat(group, s.shape[0]), s] #insert first column
m.append(group_output)
output = np.concatenate(m[::-1])
output = output[output[:,1]!= output[:,2]] #elimate slices with unit length
Выход:
[[ 0 0 16]
[ 1 0 2]
[ 1 5 14]
[ 2 0 2]
[ 2 7 14]
[ 3 1 2]
[ 3 7 13]
[ 4 7 13]
[ 5 8 12]
[ 6 10 12]
[ 8 10 12]
[ 9 11 12]]