Załóżmy, mam macierzy liczbę liczb całkowitych, jak:

[34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]

Chcę znaleźć indeksy startowe i końcowe tablicy, gdzie wartość jest więcej niż x-razy (powiedzmy 5 razy) powtórzone. Tak więc w powyższym przypadku jest to wartość 22 i 6. Wskaźnik rozpoczęcia powtarzanego 22 jest 3, a indeks końcowy wynosi 8. tak samo dla regeneracji 6. Czy istnieje specjalne narzędzie w Pythonie, który jest pomocny? W przeciwnym razie pętlałbym indeks tablicy dla indeksu i porównać rzeczywistą wartość z poprzednim.

Pozdrowienia.

9
mcatis 28 czerwiec 2017, 01:23

5 odpowiedzi

Najlepsza odpowiedź

Korzystanie z np.diff i metodę podawaną Oto przez @Warrenweckeccerser do znalezienia biegów zerowych w tablicy:

import numpy as np

def zero_runs(a):  # from link
    iszero = np.concatenate(([0], np.equal(a, 0).view(np.int8), [0]))
    absdiff = np.abs(np.diff(iszero))
    ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
    return ranges

a = [34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]

zero_runs(np.diff(a))
Out[87]: 
array([[ 3,  8],
       [15, 22]], dtype=int32)

Można to następnie przesączyć od różnicy między początkiem i końcem biegu:

runs = zero_runs(np.diff(a))

runs[runs[:, 1]-runs[:, 0]>5]  # runs of 7 or more, to illustrate filter
Out[96]: array([[15, 22]], dtype=int32)
4
EFT 27 czerwiec 2017, 23:01

Naprawdę nie jest dla tego wspaniałego krótkiego cięcia. Możesz zrobić coś w rodzaju:

mult = 5
for elem in val_list:
    target = [elem] * mult
    found_at = val_list.index(target)

Pozostawiam nieznane wyjątki i dłuższe wykrywanie sekwencji.

1
Prune 27 czerwiec 2017, 22:32

Oto stosunkowo szybki, bezkierniczy rozwiązanie, które również mówi, ile kopii był w biegu. Niektóre z tego kodu został wypożyczony z rozwiązania KAL.

# Return the start and (1-past-the-end) indices of the first instance of
# at least min_count copies of element value in container l 
def find_repeat(value, min_count, l):
  look_for = [value for _ in range(min_count)]
  for i in range(len(l)):
    count = 0
    while l[i + count] == value:
      count += 1
    if count >= min_count:
      return i, i + count
0
Liam Bohl 27 czerwiec 2017, 22:53

Jeśli szukasz value powtórzony n razy w liście L, możesz zrobić coś takiego:

def find_repeat(value, n, L):
    look_for = [value for _ in range(n)]
    for i in range(len(L)):
        if L[i] == value and L[i:i+n] == look_for:
            return i, i+n
0
KAL 27 czerwiec 2017, 22:37

Oto rozwiązanie przy użyciu natywnego {x0}.}.

Kod

import itertools as it


def find_ranges(lst, n=2):
    """Return ranges for `n` or more repeated values."""
    groups = ((k, tuple(g)) for k, g in it.groupby(enumerate(lst), lambda x: x[-1]))
    repeated = (idx_g for k, idx_g in groups if len(idx_g) >=n)
    return ((sub[0][0], sub[-1][0]) for sub in repeated)

lst = [34,2,3,22,22,22,22,22,22,18,90,5,-55,-19,22,6,6,6,6,6,6,6,6,23,53,1,5,-42,82]    
list(find_ranges(lst, 5))
# [(3, 8), (15, 22)]

Testy

import nose.tools as nt


def test_ranges(f):
    """Verify list results identifying ranges."""
    nt.eq_(list(f([])), [])
    nt.eq_(list(f([0, 1,1,1,1,1,1, 2], 5)), [(1, 6)])
    nt.eq_(list(f([1,1,1,1,1,1, 2,2, 1, 3, 1,1,1,1,1,1], 5)), [(0, 5), (10, 15)])
    nt.eq_(list(f([1,1, 2, 1,1,1,1, 2, 1,1,1], 3)), [(3, 6), (8, 10)])    
    nt.eq_(list(f([1,1,1,1, 2, 1,1,1, 2, 1,1,1,1], 3)), [(0, 3), (5, 7), (9, 12)])

test_ranges(find_ranges)

Ten przykład przechwytuje (indeks, element) pary w lst, a następnie grupuj je według elementu. Zachowano tylko wielokrotne pary. Wreszcie, pierwsze i ostatnie pary są pokrojone, wydajne (początek, końcowe) wskaźniki od każdej powtarzanej grupy.

Zobacz także Ten post do znalezienia zakresów indeksów za pomocą {X0}}.

1
pylang 5 wrzesień 2017, 19:50