Последний ответ находится в конце ответа.Было несколько исправлений.
В самом конце (4-е редактирование) ответа есть совершенно новый подход.
Я не уверен, что вы пытаетесь сделать, но, надеюсь, это можетhelp.
import numpy as np
# Generate some events
events = np.random.rand(3,12)*10.
events *= np.random.randint(5, size=(3,12))<1
events
Out[36]:
array([[ 0. , 0. , 0. , 0. , 0. ,
0. , 5.35598205, 0. , 0. , 0. ,
0. , 0. ],
[ 0. , 6.65094145, 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , 6.04581361],
[ 6.88119682, 4.31178109, 0. , 0. , 0. ,
0. , 0. , 1.16999289, 0. , 0. ,
0. , 0. ]])
# generate a boolean array of events. (as int for a compact print.)
an_event = (events != 0).astype(np.int)
n_event
Out[37]:
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]])
def event_range(arr):
from_start = arr.cumsum(axis=1)
from_end = np.flip(arr, axis=1).cumsum(axis=1)
from_end = np.flip(from_end, axis=1)
return np.logical_and(from_start, from_end).astype(np.int)
Функция event_range шаг за шагом.
from_start - это сумма an_event.ноль до любого события,> 0 после этого.
from_start = an_event.cumsum(axis=1) # cumsum the event count. zeros before the first event.
from_start
Out[40]:
array([[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], # zeroes before the first event.
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]], dtype=int32)
from_end является суммой an_event, но с макс. До мин.Следовательно, ноль после последнего события.
from_end = np.flip(an_event, axis=1).cumsum(axis=1) # cumsum of reversed arrays
from_end = np.flip(from_end, axis=1) # reverse the result.
from_end
Out[41]:
array([[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # zero after the last event.
[2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[3, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]], dtype=int32)
логически и объединение их вместе, чтобы получить, нули до первого события, единицы после этого и нули после последнего события.
ev_range = np.logical_and(from_start, from_end).astype(np.int)
ev_range
Out[42]:
# zero before first and after last event, one between the events.
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]])
n_range = ev_range.sum(axis=1)
n_range
Out[43]: array([ 1, 11, 8])
n_events = an_event.sum(axis=1)
n_events
Out[44]: array([1, 2, 3])
avg = n_range / n_events
avg
Out[45]: array([ 1. , 5.5 , 2.66666667])
Должен avgбыть n_range / (n_events-1)?то есть посчитайте промежутки, а не события.
Что вы ожидаете только для одного события подряд?Что за нулевые события в строке?
Редактировать следующие комментарии
Для подсчета промежутков длиннее нуля требуется немного времени.Самым простым является, вероятно, взять различия для последовательных столбцов.Если это -1, то за 1 следует ноль.Вам нужно добавить окончательный нулевой столбец к вашим данным, если в последнем столбце есть событие.
np.random.seed(10)
test = 1*(np.random.randint(4, size=(4,12))<1)
test
Out[24]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])
temp = np.diff(test, axis=-1)
temp
Out[26]:
array([[ 0, 1, -1, 1, -1, 0, 1, -1, 0, 1, -1],
[ 0, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0],
[ 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0]])
np.where(temp<0, 1,0)
Out[28]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]])
In [29]: np.where(temp<0, 1,0).sum(axis=-1)-1
Out[29]: array([3, 3, 1, 0]) # should be [3, 4, 1, 0]
Добавить столбец нулей для проверки.
test = np.hstack((test, np.zeros((4,1), dtype = np.int)))
test
Out[31]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]])
temp=np.diff(test, axis=-1)
temp
Out[35]:
array([[ 0, 1, -1, 1, -1, 0, 1, -1, 0, 1, -1, 0],
[ 0, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0, -1], # An extra -1 here.
[ 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0]])
np.where(temp<0, 1,0).sum(axis=-1)-1
Out[36]: array([3, 4, 1, 0])
Как ясказал, немного вовлечен.Может быть легче пройти через цикл, но это должно быть быстрее, если труднее понять.
2nd Edit, следуя другой идее.
import numpy as np
np.random.seed(10)
test = 1*(np.random.randint(4, size=(4,12))<1)
test
Out[2]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])
temp = np.diff(test, axis=-1)
np.where(temp<0, 1, 0).sum(axis=-1)+test[:,-1]-1
# +test[:,-1] adds the last column to include any 1's from there.
Out[4]: array([3, 4, 1, 0])
3rd Edit
Думая об этом, я создал 2 функции, я также показываю do_divide, который справляется с делением на ноль.
import numpy as np
def zero_after_last_event(arr):
"""
Returns an array set to zero in all cells after the last event
"""
from_end = np.flip(arr, axis=-1).cumsum(axis=-1) # cumsum of reversed arrays
from_end = np.flip(from_end, axis=-1) # reverse the result.
from_end[from_end>0] = 1 # gt zero set to 1
return from_end
def event_range(arr):
""" event_range is zero before the first event,
zero after the last event and 1 elsewhere. """
return np.logical_and(arr.cumsum(axis=-1), zero_after_last_event(arr)).astype(np.int)
def do_divide(a, b):
""" Does a protected divide. Returns zero for divide by zero """
with np.errstate(invalid='ignore'): # Catch divide by zero
result = a / b
result[~np.isfinite(result)] = 0.
return result
Настройка тестового массива
np.random.seed(10)
events = 1*(np.random.randint(4, size=(4,12))<1)
events
Out[15]:
array([[0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]])
С вышеприведенными функциями и данными это следует.
# Count gap lengths
gaps = 1 - events # invert the values in events (1->0, 0->1)
gaps = np.logical_and(gaps, event_range(events)).astype(np.int)
gaps
Out[19]:
array([[0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
sumgaps = gaps.sum(axis = -1)
sumgaps
Out[22]: array([5, 4, 4, 0])
# Count how many gaps
temp = np.diff(events, axis=-1) # temp is -1 when an event isn't immediately followed by another event.
n_gaps = np.where(temp<0, 1, 0).sum(axis=-1)+events[:,-1]-1
# +test[:,-1] adds the last column to include any 1's from there.
n_gaps
Out[23]: array([3, 4, 1, 0])
do_divide(sum_gaps, n_gaps)
Out[21]: array([1.66666667, 1. , 4. , 0. ])
4-е редактирование - с использованием np.bincount
import numpy as np
def do_divide(a, b):
""" Does a protected divide. Returns zero for divide by zero """
with np.errstate(invalid='ignore'): # Catch divide by zero
result = a / b
result[~np.isfinite(result)] = 0.
return result
np.random.seed(10)
events = 1*(np.random.randint(4, size=(4,12))<1)
cumulative = events.cumsum(axis=1)
cumulative
Out[2]:
array([[0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4],
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6],
[0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 3, 3],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]])
bin_count_len = 1+cumulative.max() # Biggest bins length required.
result = np.zeros((cumulative.shape[0], bin_count_len), dtype=np.int)
for ix, row in enumerate(cumulative):
result[ix] = np.bincount( row, minlength = bin_count_len )
result
Out[4]:
array([[2, 2, 3, 3, 2, 0, 0],
[2, 2, 2, 2, 2, 1, 1],
[3, 5, 1, 3, 0, 0, 0],
[9, 3, 0, 0, 0, 0, 0]])
Потерять столбец 0. Его перед любымСобытия.Потерять последний столбец, всегда после последнего события.Пробелы включают в себя событие открытия, -1 удаляет его из размера пробела.
temp = result[:, 1:-1]-1 #
temp
Out[6]:
array([[ 1, 2, 2, 1, -1],
[ 1, 1, 1, 1, 0],
[ 4, 0, 2, -1, -1],
[ 2, -1, -1, -1, -1]])
Установите любую ячейку temp [r, n] = 0, если temp [r, n + 1] == 0
temp_lag = (result[:, 2:]>0)*1
temp_lag
Out[8]:
array([[1, 1, 1, 0, 0],
[1, 1, 1, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 0, 0, 0]])
temp *= temp_lag
temp
Out[10]:
array([[1, 2, 2, 0, 0],
[1, 1, 1, 1, 0],
[4, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
tot_gaps = temp.sum(axis=1)
n_gaps = np.count_nonzero(temp, axis=1)
tot_gaps, n_gaps
Out[13]: (array([5, 4, 4, 0]), array([3, 4, 1, 0]))
do_divide(tot_gaps, n_gaps)
Out[14]: array([1.66666667, 1. , 4. , 0. ])
HTH