2015-12-04 2 views
1

У меня есть Numpy массив вида: arr = 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1Изменение NumPy массива, чтобы получить минимальное количество значений между элементами

Я хотел бы изменить его таким образом, что существует семь зарегистрировано не менее 0s между любыми двумя 1s. Если есть меньше семи 0, то конвертируйте интервал 1 в 0. Я думаю, что numpy.where мог бы работать здесь, но не уверен, как это сделать в succint, pythonic образом:

Результат должен выглядеть как это:

0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 

numpy.where(arr[:] > 1.0, 1.0, 0.0) 
+3

'np.where' этого не сделает. Учитывая, насколько по сути проблема с состоянием - проблема в том, что какой-либо 1 стирается, в значительной степени зависит от предыдущих решений о стирании - я сомневаюсь, что есть хороший способ сделать это с помощью операций NumPy. – user2357112

+0

спасибо @ user2357112, поэтому я должен вернуться к циклам? – user308827

+0

Это один из вариантов. Вы также можете попробовать подходы, которые стирают больше элементов, чем необходимо, или попробовать некоторые действительно взломанные вещи с помощью соответствующего метода ufunc 'at' и переходящего окна. – user2357112

ответ

2

следующий код действительно уродливые взломать, но он получает работу в линейное время (в предположении, 7 фиксировано), не прибегая к Python петель и без необходимости ничего подобного Numba или Cython. Я не рекомендую использовать его, особенно если в следующем месяце 7 может составлять 700.

def rolling_window(a, window): 
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) 
    strides = a.strides + (a.strides[-1],) 
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 

arr2 = numpy.append(1-arr, [0]*7) 
numpy.power.at(rolling_window(arr2[1:], 7), np.arange(len(arr)), arr2[:-7, None]) 
arr = 1 - arr2[:-7] 

Он работает путем установки 1s на 0 и наоборот, то для каждого элемента x, устанавливая каждый элемент y в ближайшие 7 мест для y**x, затем расстегивать переключатель 0/1. Операция питания устанавливает все в пределах 7 пробелов от 0 до 1, таким образом, чтобы эффект сразу отображался для операций электропитания дальше по массиву.

+0

спасибо @ user2357112, почему бы вам не рекомендовать ваш soln для 700 вместо 7? проблемы скорости? – user308827

+1

@ пользователь308827: скорость проблема. Это берет 'O (window * len (arr))' время, где 'arr' - это массив, который вы обрабатываете, а' window' - сколько 0-х вам нужно между последовательными 1-м. Кроме того, независимо от скорости, этот код трудно понять, подвержен ошибкам и действительно странный. – user2357112

1

Теперь это простая реализация, использующая для циклов и ifs, но я уверен, что она может быть сжата. (Много!) И да, нет необходимости делать Numpy для этого, это только усложнит вам все.

question = [0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1] 
result = [0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1] 
indexesOf1s = [] 
for index,item in enumerate(question):  #Here just calculate all the index of 1s 
if item == 1: 
    indexesOf1s.append(index) 
for i in indexesOf1s:    #Iterate over the indexes and change acc to conditions 
    sub = i - indexes[indexes.index(i)-1] 
    if sub>0 and sub>=7: 
     question[i] = 1 
    elif sub>0: 
     question[i] = 0 
print question 
print result 
Смежные вопросы