Problems with Numpy.where function and syntax - python

I am working on some code to create a table of data and have run into an issue. Early on in the code I create a range of speeds that the program needs to check with the following:
Vskn=np.linspace(Vl,Vh, num=int ((Vh-Vl)*2+1))
For each Vskn I then compute the FN and Frcrit, which are separate functions that use the Vskn list... Basically I need the FN and Frcrit for each speed.
Later on in the code I need to determine if FN or Frcrit is higher, then do some calculations to them based on that result. I have tried each of the following, and neither work.
np.where(FN<Frcrit[kFrm=1,kFrm=(FN/Frcrit)**c1dm])
Results in a "SyntaxError: invalid syntax"
#if FN<Frcrit:
# kFrm=1
#else:
# kFrm=(FN/Frcrit)**c1dm
Results in a "ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"
How do I resolve this?

Your syntax is just a little off. When using numpy, it's often easier to use indexing directly rather than using where. So, if kFrm already exists, then you can index into kFrm "where" FN < Frcrit and set it to 1, and similarly index into kFrm "where" FN >= Frcrit and set it equal to your equation. I'm also indexing into greater_than_vals to make the shapes work.
kFrm[FN < Frcrit] = 1
greater_than_vals = (FN / Frcrit) ** c1dm
kFrm[FN >= Frcrit] = greater_than_vals[FN >= Frcrit]
If kFrm doesn't exist yet, then you can do:
kFrm = np.ones_like(FN)
greater_than_vals = (FN / Frcrit) ** c1dm
kFrm[FN >= Frcrit] = greater_than_vals[FN >= Frcrit]

Related

How to iterate over external input list in pyomo objective function?

I am trying to run a simple LP pyomo Concrete model with Gurobisolver :
import pyomo.environ as pyo
from pyomo.opt import SolverFactory
model = pyo.ConcreteModel()
nb_years = 3
nb_mins = 2
step = 8760*1.5
delta = 10000
#Range of hour
model.h = pyo.RangeSet(0,8760*nb_years-1)
#Individual minimums
model.min = pyo.RangeSet(0, nb_mins-1)
model.mins = pyo.Var(model.min, within=model.h, initialize=[i for i in model.min])
def maximal_step_between_mins_constraint_rule(model, min):
next_min = min + 1 if min < nb_mins-1 else 0
if next_min == 0: # We need to take circularity into account
return 8760*nb_years - model.mins[min] + model.mins[next_min] <= step + delta
return model.mins[next_min] - model.mins[min] <= step + delta
def minimal_step_between_mins_constraint_rule(model, min):
next_min = min + 1 if min < nb_mins-1 else 0
if next_min == 0: # We need to take circularity into account
return 8760*nb_years - model.mins[min] + model.mins[next_min] >= step - delta
return model.mins[next_min] - model.mins[min] >= step - delta
model.input_list = pyo.Param(model.h, initialize=my_input_list, within=pyo.Reals, mutable=False)
def objective_rule(model):
return sum([model.input_list[model.mins[min]] for min in model.min])
model.maximal_step_between_mins_constraint= pyo.Constraint(model.min, rule=maximal_step_between_mins_constraint_rule)
model.minimal_step_between_mins_constraint= pyo.Constraint(model.min, rule=minimal_step_between_mins_constraint_rule)
model.objective = pyo.Objective(rule=objective_rule, sense=pyo.minimize)
opt = SolverFactory('gurobi')
results = opt.solve(model, options={'Presolve':2})
Basically I am trying to find two hours in my input list (which looks like this) spanning over 3 years of data, with constraints on the distance separating them, and where the sum of both value is minimized by the model.
I implemented my list as a parameter of fixed value, however even if mutable is set to False running my model produces this error :
ERROR: Rule failed when generating expression for Objective objective with
index None: RuntimeError: Error retrieving the value of an indexed item
input_list: index 0 is not a constant value. This is likely not what you
meant to do, as if you later change the fixed value of the object this
lookup will not change. If you understand the implications of using non-
constant values, you can get the current value of the object using the
value() function.
ERROR: Constructing component 'objective' from data=None failed: RuntimeError:
Error retrieving the value of an indexed item input_list: index 0 is not a
constant value. This is likely not what you meant to do, as if you later
change the fixed value of the object this lookup will not change. If you
understand the implications of using non-constant values, you can get the
current value of the object using the value() function.
Any idea why I get this error and how to fix it ?
Obviously, changing the objective function to sum([pyo.value(model.input_list[model.mins[min]]) for min in model.min]) is not a solution to my problem.
I also tried not to use pyomo parameters (with something like sum([input_list[model.mins[min]] for min in model.min]), but pyomo can't iterate over it and raises the following error :
ERROR: Constructing component 'objective' from data=None failed: TypeError:
list indices must be integers or slices, not _GeneralVarData
You have a couple serious syntax and structure problems in your model. Not all of the elements are included in the code you provide, but you (minimally) need to fix these:
In this snippet, you are initializing the value of each variable to a list, which is invalid. Start with no variable initializations:
model.mins = pyo.Var(model.min, within=model.h, initialize=[i for i in model.min])
In this summation, you appear to be using a variable as the index for some data. This is an invalid construct. The value of the variable is unkown when the model is built. You need to reformulate:
return sum([model.input_list[model.mins[min]] for min in model.min])
My suggestion: Start with a very small chunk of your data and pprint() your model and read it carefully for quality before you attempt to solve.
model.pprint()

Efficiently assign a value within predefined range in Numpy

The objective is to assign new value within certain range (b_top,b_low).
The code below able to achieve the intended objective
b_top=np.array([1,7])
b_low=np.array([3,9])+1
Mask=np.zeros((1,11), dtype=bool)
for x,y in zip(b_top,b_low):
Mask[0,x:y]=True
However, I wonder there is single line approach, or more efficient way of doing this?
You can turn b_top and b_low into a mask using np.cumsum and the fact that bool and int8 are the same itemsize.
header = np.zeros(M.shape[1], np.uint8)
header[b_top] = 1
header[b_low if b_low[-1] < header.size else b_low[:-1]] = -1
header.cumsum(out=Mask[0].view(np.int8))
I've implemented this function in a little utility library I made. The function is called haggis.math.runs2mask. You would call it as
from haggis.math import runs2mask
Mask[0] = runs2mask(np.stack((b_top, b_low), -1), Mask.shape[1])

Error in selecting indeces of a list divisimple by a given value

a simple code:
suka = pd.Series(range(10))
padla =np.argwhere(suka % 4==0)
get the error Length of passed values is 1, index implies 10. Why the machine can't return the requested indices? Thank you.
The fundamental issues are that the semantics of an array and a DataFrame is significantly different (and hence the return of np.argwhere shouldn't be boxed) and numpy only passing context for ufuncs (hence we don't know np.argwhere is the function calling array_wrap)
This is an issue with the new release of pandas occur in Pandas 1.0.1 and later versions.
Try np.flatnonzero() insted of np.argwhere()
Code is :
suka = pd.Series(range(10))
padla =np.flatnonzero(suka % 4==0)
for more details go to https://github.com/numpy/numpy/issues/15555 and https://github.com/pandas-dev/pandas/pull/35334
IF you're using pandas the way to identify args is index, which is separate to their actual order, so pandas approach would be to define padla as:
padla = (suka % 4 == 0)
padla = padla.loc[padla].index
Roughly speaking equivalent for numpy will be:
padla = np.argwhere((suka % 4 == 0).values)

Python Pandas: How to pass two or more arguments/ column-values to a custom function using .apply ()

I am trying to write a custom function which takes 3 inputs and is basically checking the length of Full Name(First+Last) > Occupation.I have tries 2 variations of apply but both are giving an error. PS I am rookie in Python and Pandas area.
def check(fname,lname,occu):
if(len(fname)+len(lname)>len(occu)):
return True
else:
return False
customers.apply(lambda x: check(x['First Name'],x['Last Name'],x['Occupation']),axis=1)
The immediate error is probably a typo, i.e. you need len(lname) rather than lname(lname). But you don't need a row-wise loop. You can call pd.Series.str.len instead:
df['CheckFlag'] = (df['First Name'].str.len() + df['Last Name'].str.len()) > \
df['Occupation'].str.len()

Python: "Use a.any() or a.all()" while traversing a numpy.ndarray

In a numpy.ndarray like this one:
myarray=
array([[ 0.47174344, 0.45314669, 0.46395022, 0.47440382, 0.50709627,
0.53350065, 0.5233444 , 0.49974663, 0.48721607, 0.46239652,
0.4693633 , 0.47263569, 0.47591957, 0.436558 , 0.43335574,
0.44053621, 0.42814804, 0.43201894, 0.43973886, 0.44125302,
0.41176999],
[ 0.46509004, 0.46221505, 0.48824086, 0.50088744, 0.53040384,
0.53592231, 0.49710228, 0.49821022, 0.47720381, 0.49096272,
0.50438366, 0.47173162, 0.48813669, 0.45032002, 0.44776794,
0.43910269, 0.43326132, 0.42064458, 0.43472954, 0.45577299,
0.43604956]])
I want to count how many cells exceed a given value, let's say 0.5, and set those that don't to 0.0. This is what I do:
count=0
value=0.5
for i in range(myarray.shape[0]):
for j in range(myarray.shape[1]):
if myarray[i][j]<value:
myarray[i][j]=0
elif myarray[i][j]>=value:
count=count+1
percentage=round(100*count/(myarray.shape[0]*myarray.shape[1]),2)
However, I get this error: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all(), pointing at the line where I check if myarray[i][j]<value.
Why does this happen and how to fix it? What is the truth value?
Normally, you can compare two numbers to get a truth value. For example:
elem = 5
if elem < 6:
# do something
is equivalent to:
if true:
# do something
However, you can't compare an array to a value. For example:
elem = [5,7]
if elem < 6:
# this doesn't make sense
Instead, you can get the truth value of whether any or all elements satisfy the condition. For example:
elem = np.array([5,7])
if np.any(elem<6):
# this is true, because 5 < 6
if np.all(elem<6):
# this isn't true, because 7 > 6
I ran your example code above and found no error, so I'm not sure what the issue is. But this is what you should look out for. Consider printing the element you are comparing to see if it is an array.
Also, this is a shorter way of doing what you want to do:
myarray = np.array( putarrayhere )
count = sum(myarray >= value)
Yeah I think your numpy.array has an extra bracket or it is encompassing another array.
Tried Manually set array as
myarray=np.array([[ 0.47174344, 0.45314669, 0.46395022, 0.47440382, 0.50709627,0.53350065, 0.5233444 , 0.49974663, 0.48721607, 0.46239652, 0.4693633 , 0.47263569, 0.47591957, 0.436558 , 0.43335574,0.44053621, 0.42814804, 0.43201894, 0.43973886, 0.44125302, 0.41176999],[ 0.46509004, 0.46221505, 0.48824086, 0.50088744, 0.53040384,0.53592231, 0.49710228, 0.49821022, 0.47720381, 0.49096272,0.50438366, 0.47173162, 0.48813669, 0.45032002, 0.44776794,0.43910269, 0.43326132, 0.42064458, 0.43472954, 0.45577299,0.43604956]])
and the code works
but setting:
myarray=np.array([[[ 0.47174344, 0.45314669, 0.46395022, 0.47440382, 0.50709627,0.53350065, 0.5233444 , 0.49974663, 0.48721607, 0.46239652, 0.4693633 , 0.47263569, 0.47591957, 0.436558 , 0.43335574,0.44053621, 0.42814804, 0.43201894, 0.43973886, 0.44125302, 0.41176999],[ 0.46509004, 0.46221505, 0.48824086, 0.50088744, 0.53040384,0.53592231, 0.49710228, 0.49821022, 0.47720381, 0.49096272,0.50438366, 0.47173162, 0.48813669, 0.45032002, 0.44776794,0.43910269, 0.43326132, 0.42064458, 0.43472954, 0.45577299,0.43604956]]])
yielded similar errors
Regardless the error you can simply do:
myarray[myarray<value]=0
np.count_nonzero(myarray)
to get your desired result

Categories

Resources