Значение истинности массива с более чем одним элементом неоднозначно. Используйте a.any() или a.all()

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

def f(x,d,h,L):
    ans=0.
    if ((0.<=x) & (x<d)):
        ans=h*(x/d)
    elif ((d<=x) & (x<=L)):
        ans=((L-x)/(L-d))
    return ans

x=np.linspace(0,10,1000)
h=5*10**(-3)
d=16*10**(-2)
L=64.52*10**(-2)
func=f(x,d,h,L)

Но когда я пытаюсь запустить его, я получаю сообщение об ошибке, указывающее на строку if с кодом ошибки в заголовке, я пробовал предложенные решения, приведенные в аналогичных вопросах, таких как использование np.logical_and или and вместо &, но все три дают одну и ту же ошибку , пожалуйста, помогите мне


person JuanGiraldo    schedule 29.06.2015    source источник
comment
x - это массив. Вы хотите, чтобы f выполнял одно действие, если некоторые/все x попадают в один диапазон, и другое, если они не попадают? Или вы хотите, чтобы он делал одно действие со значениями x, попадающими в один диапазон, и другое — с другими значениями x? Другими словами, применяется ли тест if ко всему x или к отдельным элементам?   -  person hpaulj    schedule 30.06.2015
comment
Другой способ поставить мой вопрос - правильно ли работает функция, если вы передаете ей элементы x по отдельности?   -  person hpaulj    schedule 30.06.2015


Ответы (5)


Используйте numpy.где. При необходимости используйте экспоненциальную запись для чисел с плавающей запятой.

import numpy as np

def f(x, d, h, L):
    return np.where(x < d, h*(x/d), (L - x)/(L - d))

x = np.linspace(0,10,1000)
h = 5e-3
d = 16e-2
L = 64.52e-2

func = f(x, d, h, L)
person Pedro López-Adeva    schedule 30.06.2015

Вы сосредотачиваетесь на соединении предложений, но это сами предложения. Вы, вероятно, хотите здесь что-то вроде:

if numpy.all(0 <= x) and numpy.all(x < d):
    ...

См. документы для numpy.all.

person Ami Tavory    schedule 29.06.2015
comment
Возможная альтернатива — numpy.all((0 <= x) & (x < d)):, но из соображений удобочитаемости я бы этого не рекомендовал. - person ; 30.06.2015
comment
@Evert Спасибо, хотя я на самом деле думаю, что версия в ответе выигрывает от короткого замыкания, а это нет, не так ли? - person Ami Tavory; 30.06.2015
comment
С учетом x и других параметров эти all тесты возвращают False, то есть f просто возвращает 0.. - person hpaulj; 30.06.2015

Я смог решить свою проблему, определив x как массив и создав цикл для оценки каждого x по отдельности, не уверен, что это самый эффективный способ сделать это, но я работаю только с 1000 итераций, так что это работает хорошо, вот что Я сделал:

def f(a,d,h,L):
ans2=[]
for i in range(1000):
    if (0.<=a[i]) & (a[i]<d):
        ans=x[i]*(h/d)
        ans2.append(ans)
    elif ((d<=a[i]) & (a[i]<=L)):
        ans=h*((L-a[i])/(L-d))
        ans2.append(ans)
return ans2
L=64.52*10**(-2)
x=np.linspace(0,L,1000)
h=5*10**(-3)
d=16*10**(-2)
plot.plot(x,f(x,d,h,L))

Надеюсь, что это также решит чью-то проблему, и если его можно оптимизировать, чтобы он работал быстрее, я хотел бы узнать, как это сделать.

person JuanGiraldo    schedule 30.06.2015

Ошибка связана с тем, что массив содержит больше значения. Например, a < 0, где a = 1 имеет окончательное значение истинности (ложь). Однако что, если a является массивом. например [-1, 0, 1], некоторые элементы меньше нуля, а некоторые больше или равны нулю. Так какой же должна быть истинная ценность? Чтобы иметь возможность создать значение истинности, вы должны указать, хотите ли вы, чтобы все значения были меньше нуля, или чтобы хотя бы одно значение было меньше нуля (любое > значение).

Поскольку математические операторы над массивами numpy сами возвращают массивы, мы можем вызвать all или any для этих массивов, чтобы проверить, все или хотя бы одно значение правдиво. Вы бы переписали свой оператор if как:

if (0 <= x).all() and (x < d).all():
    ...
# alternatively
if 0 <= x.min() and x.max() < d:
    ...
person Dunes    schedule 29.06.2015

Другие ответили, предполагая, что вы хотите применить тот или иной расчет в зависимости от того, соответствуют ли все/любые значения x соответствующим условиям. Я сделаю другое предположение: вы хотите применить f к каждому элементу x по отдельности.

Применяя элемент за элементом, я получаю:

In [226]: x=np.linspace(0,1,20)

In [227]: [f(z,d,h,L) for z in x]
Out[227]: 
[0.0,
 0.0016447368421052631,
 0.0032894736842105261,
 0.0049342105263157892,
 0.89586497157981526,
 0.78739098364212268,
 0.6789169957044302,
 0.57044300776673762,
 0.46196901982904509,
 0.35349503189135251,
 0.24502104395365998,
 0.13654705601596731,
 0.028073068078274897,
 0.0,
 0.0,
 0.0,
 0.0,
 0.0,
 0.0,
 0.0]

Векторизованный эквивалент:

In [238]: I = (0<=x) & (x<d)
In [239]: J=(d<=x) & (x<=L)

In [240]: out=np.zeros_like(x)
In [241]: out[I]=h*(x[I]/d)
In [242]: out[J]=(L-x[J])/(L-d)

In [243]: out
Out[243]: 
array([ 0.        ,  0.00164474,  0.00328947,  0.00493421,  0.89586497,
        0.78739098,  0.678917  ,  0.57044301,  0.46196902,  0.35349503,
        0.24502104,  0.13654706,  0.02807307,  0.        ,  0.        ,
        0.        ,  0.        ,  0.        ,  0.        ,  0.        ])

Я позволю вам упаковать это как функцию.


С указанными параметрами (включая полный x) np.all(I) и np.all(J) оба являются False, что означает, что f вернет 0.0, если будет применено к x в целом.


def f(x, d, h, L):
   I = (0<=x) & (x<d)
   J=(d<=x) & (x<=L)
   out=np.zeros_like(x)
   out[I]=h*(x[I]/d)
   out[J]=(L-x[J])/(L-d)
   return out
person hpaulj    schedule 30.06.2015
comment
Привет. ваш ответ больше похож на то, что я ищу, однако, как я могу превратить это в функцию x? Я пытаюсь построить график x vs. y, который должен выглядеть как треугольник, левая сторона которого круче правой, высота h, расстояние от нуля до < i>L, а d — расстояние по x до точки, где y=h - person JuanGiraldo; 30.06.2015
comment
Я добавил версию функции. - person hpaulj; 30.06.2015