Подсчитать количество одинаковых значений в столбце внутри массива - PullRequest
0 голосов
/ 26 августа 2018

Я ищу решение следующей проблемы:

Допустим, у меня есть массив с формой (4, 4):

[5. 4. 5. 4.]
[2. 3. 5. 5.]
[2. 1. 5. 1.]
[1. 3. 1. 3.]

В этом массиве есть одинстолбец, в котором значение «5» появляется 3 раза подряд.То есть они не разбросаны по столбцу, как показано ниже.

[5.] # This
[1.] # Should
[5.] # Not
[5.] # Count

Теперь давайте предположим, что у меня есть больший массив с формой (M, N) и различными целочисленными значениями в том же диапазоне 1-5.Как бы я подсчитал максимальное количество одинаковых значений в строке на столбец?Кроме того, возможно ли получить индексы, в которых эти значения появятся?Ожидаемый результат вышеприведенного примера будет

Found 3 in a row of number 5 in column 2
(0,2), (1,2), (2,2)

Я предполагаю, что реализация будет аналогичной, если поиск будет касаться строк.Если бы не я, я бы хотел знать, как это делается.

Ответы [ 3 ]

0 голосов
/ 26 августа 2018

Если мы сохраним максимальную длину серии идентичных значений в столбце в переменной, то мы сможем выполнить итерацию для поиска циклов большей длины.

Если следующее требует дополнительных пояснений, просто скажите!

a = np.array([[5,4,5,4],[2,3,5,5],[2,1,5,1],[1,3,1,3]])
rows, cols = a.shape
max_length = 0
for ci in range(cols):
    for ri in range(rows):
         if ri == 0:                  #start of run
             start_pos = (ri, ci)
             length = 1
         elif a[ri,ci] == a[ri-1,ci]: #during run
             length += 1
         else:                        #end of run
             if length > max_length:
                 max_length = length
                 max_pos = start_pos

max_row, max_col = max_pos
print('Found {} in a row of number {} in column {}'.format(max_length, a[max_pos], max_col))
for i in range(max_length):
     print((max_row+i, max_col))

Вывод:

Found 3 in a row of number 5 in column 2
(0, 2)
(1, 2)
(2, 2)

Обратите внимание, что если вы хотите, чтобы вывод кортежей был в указанном вами формате, вы можете использоватьгенератор-выражение с str.join:

print((max_row+i, max_col) for i in range(max_length)
0 голосов
/ 27 августа 2018

Другой подход заключается в использовании itertools.groupby , как предлагает @user, возможная реализация заключается в следующем:

import numpy as np
from itertools import groupby


def runs(column):
    max_run_length, start, indices, max_value = -1, 0, 0, 0
    for val, run in groupby(column):
        run_length = sum(1 for _ in run)
        if run_length > max_run_length:
            max_run_length, start, max_value = run_length, indices, val
        indices += run_length

    return max_value, max_run_length, start

Вышеприведенная функция вычисляет длину максимального прогона, начало и соответствующее значение для данного столбца (строки). С этими значениями вы можете рассчитать ожидаемый результат. Groupby - это тот, кто выполняет всю тяжелую работу, для массива [5., 5., 5., 1.],

[(val, sum(1 for _ in run)) for val, run in groupby([5., 5., 5., 1.])]

предыдущая строка выводит: [(5.0, 3), (1.0, 1)]. Цикл хранит начальный индекс наибольшего прогона, его длину и значения. Чтобы применить функцию к столбцам, вы можете использовать numpy.apply_along_axis

data = np.array([[5., 4., 5., 4.],
                 [2., 3., 5., 5.],
                 [2., 1., 5., 1.],
                 [1., 3., 1., 3.]])

result = [tuple(row) for row in np.apply_along_axis(runs, 0, data).T]
print(result)

выход

[(2.0, 2.0, 1.0), (4.0, 1.0, 0.0), (5.0, 3.0, 0.0), (4.0, 1.0, 0.0)]

На выходе выше четвертого кортежа соответствует четвертому столбцу значение самого длинного последовательного прогона равно 5, длина равна 3 и начинается с индекса 0. Чтобы изменить строки вместо столбцов, измените индекс оси на 1 и отбросьте букву T, например:

result = [tuple(row) for row in np.apply_along_axis(runs, 1, data)]

выход

[(5.0, 1.0, 0.0), (5.0, 2.0, 2.0), (2.0, 1.0, 0.0), (1.0, 1.0, 0.0)]
0 голосов
/ 26 августа 2018

Подход № 1

Вот один подход -

def find_longest_island_indices(a, values):
    b = np.pad(a, ((1,1),(0,0)), 'constant')
    shp = np.array(b.shape)[::-1] - [0,1]
    maxlens = []
    final_out = []
    for v in values:
        m = b==v        
        idx = np.flatnonzero((m[:-1] != m[1:]).T)
        s0,s1 = idx[::2], idx[1::2]        
        l = s1-s0
        maxidx = l.argmax()
        longest_island_flatidx = np.r_[s0[maxidx]:s1[maxidx]]            
        r,c = np.unravel_index(longest_island_flatidx, shp)
        final_out.append(np.c_[c,r])
        maxlens.append(l[maxidx])
    return maxlens, final_out

Пробный прогон -

In [169]: a
Out[169]: 
array([[5, 4, 5, 4],
       [2, 3, 5, 5],
       [2, 1, 5, 1],
       [1, 3, 1, 3]])

In [173]: maxlens
Out[173]: [1, 2, 1, 1, 3]

In [174]: out
Out[174]: 
[array([[3, 0]]), array([[1, 0],
        [2, 0]]), array([[1, 1]]), array([[0, 1]]), array([[0, 2],
        [1, 2],
        [2, 2]])]

# With "pretty" printing
In [171]: maxlens, out = find_longest_island_indices(a, [1,2,3,4,5])
     ...: for  l,o,i in zip(maxlens,out,[1,2,3,4,5]):
     ...:     print "For "+str(i)+" : L= "+str(l)+", Idx = "+str(o.tolist())
For 1 : L= 1, Idx = [[3, 0]]
For 2 : L= 2, Idx = [[1, 0], [2, 0]]
For 3 : L= 1, Idx = [[1, 1]]
For 4 : L= 1, Idx = [[0, 1]]
For 5 : L= 3, Idx = [[0, 2], [1, 2], [2, 2]]

Подход № 2

С небольшим изменением и выводом индексов начала и конца для острова максимальной длины, вот один -

def find_longest_island_indices_v2(a, values):
    b = np.pad(a.T, ((0,0),(1,1)), 'constant')
    shp = b.shape
    out = []
    for v in values:
        m = b==v        
        idx = np.flatnonzero(m.flat[:-1] != m.flat[1:])
        s0,s1 = idx[::2], idx[1::2]        
        l = s1-s0
        maxidx = l.argmax()
        start_index = np.unravel_index(s0[maxidx], shp)[::-1]
        end_index = np.unravel_index(s1[maxidx]-1, shp)[::-1]
        maxlen = l[maxidx]
        out.append([v,maxlen, start_index, end_index])
    return out  

Пример выполнения -

In [251]: a
Out[251]: 
array([[5, 4, 5, 4],
       [2, 3, 5, 5],
       [2, 1, 5, 1],
       [1, 3, 1, 3]])

In [252]: out = find_longest_island_indices_v2(a, [1,2,3,4,5])

In [255]: out
Out[255]: 
[[1, 1, (3, 0), (3, 0)],
 [2, 2, (1, 0), (2, 0)],
 [3, 1, (1, 1), (1, 1)],
 [4, 1, (0, 1), (0, 1)],
 [5, 3, (0, 2), (2, 2)]]

# With some pandas styled printing 
In [253]: import pandas as pd

In [254]: pd.DataFrame(out, columns=['Val','MaxLen','StartIdx','EndIdx'])
Out[254]: 
   Val  MaxLen StartIdx  EndIdx
0    1       1   (3, 0)  (3, 0)
1    2       2   (1, 0)  (2, 0)
2    3       1   (1, 1)  (1, 1)
3    4       1   (0, 1)  (0, 1)
4    5       3   (0, 2)  (2, 2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...