Python: условные элементы в массиве - PullRequest
2 голосов
/ 29 сентября 2011

Вопрос от новичка в Python.

У меня есть массив столбцов, в котором мне нужно принудительно установить некоторые значения в ноль в зависимости от условного выражения, примененного к другому массиву. Я нашел два решения, которые оба дают правильный ответ. Но они оба довольно трудоемки для больших массивов, которые мне обычно нужны (> 1E6 элементов) - также я подозреваю, что это плохая методика программирования. Две версии:

from numpy import zeros,abs,multiply,array,reshape

def testA(y, f, FC1, FC2):
    c = zeros((len(f),1))
    for n in xrange(len(f)):
        if abs(f[n,0]) >= FC1 and abs(f[n,0]) <= FC2:
            c[n,0] = 1.
    w = multiply(c,y)
    return w

def testB(y, f, FC1, FC2):
    z = [(abs(f[n,0])>=FC1 and abs(f[n,0])<=FC2) for n in xrange(len(f))]
    z = multiply(array(z,dtype=float).reshape(len(f),1), y)
    return z

Входные массивы являются массивами столбцов, поскольку это соответствует последующей обработке, которая должна быть выполнена. Тест можно сделать так:

>>> from numpy.random import normal as randn
>>> fs, N = 1.E3, 2**22
>>> f = fs/N*arange(N).reshape((N,1))
>>> x = randn(size=(N,1))
>>> w1 = testA(x,f,200.,550.)
>>> z1 = testB(x,f,200.,550.)

На моем ноутбуке testA занимает 18,7 секунды, а testB - 19,3 - оба для N = 2 ** 22. В testB я также пытался включить «z = [None] * len (f)» для предварительного выделения, как это предлагается в другом потоке, но это на самом деле не имеет никакого значения.

У меня есть два вопроса, на которые я надеюсь получить один и тот же ответ:

  1. Какое «правильное» решение Python для этой проблемы?
  2. Могу ли я что-нибудь сделать, чтобы получить ответ быстрее?

Я специально не использовал время вообще, например, на скомпилированном Python - сначала я хотел получить какой-нибудь рабочий код. Надеюсь, что-то, что является хорошим стилем Python. Я надеюсь, что смогу получить время выполнения для N = 2 ** 22 ниже двух секунд или около того. Эта конкретная операция будет использоваться много раз, поэтому время выполнения имеет значение.

Заранее извиняюсь, если вопрос глупый - мне не удалось найти ответ в подавляющем количестве не всегда легко доступной документации по Python или в другой ветке.

Ответы [ 2 ]

5 голосов
/ 29 сентября 2011

использовать массив bool для доступа к элементам в массиве y:

def testC(y, f, FC1, FC2):
    f2 = abs(f)
    idx = (f2>=FC1) & (f2<=FC2)
    y[~idx] = 0
    return y
0 голосов
/ 29 сентября 2011

Все это медленнее, чем решение HYRY, по большому счету:

Как насчет

( x[1] if FC1<=abs(x[0])<=FC2 else 0 for x in itertools.izip(f,x) )

Если вам нужно сделать произвольный доступ (очень медленно)

[ x[1] if FC1<=abs(x[0])<=FC2 else 0 for x in itertools.izip(f,x) ]

или вы также можете использовать карту

map(lambda x: x[1] if FC1<=abs(x[0])<=FC2 else 0 , itertools,izip(f,x))

или с использованием векторизации (быстрее, чем A и B, но намного медленнее, чем C)

b1v = np.vectorize(lambda a,b: a if 200<=abs(b)<=550 else 0)
b1 = b1v(f,x)
...