Can't define a term in Python - python

First post so I'll try to be specific as possible.
I'm trying to define a term ybar1 in Python. I'm intending for ybar1 to be the average of a list y1
where y1 = [1, 2, 3, 4, 5]
What I'm doing first is:
import numpy as np
then defining a new function
def funk(y1):
print np.sum(y1)/len(y1)
return;
So now when I compute funk(y1) I get a number, 3
Now is where it gets weird. I try to say:
ybar1 = funk(y1)
, which returns the value 3
but then when I type ybar1 alone, I get no output.
Thoughts?

Try this:
def funk(y1):
return np.sum(y1)/len(y1)
You were not actually returning a value from the function, only printing a result on the console. Also, there's a better way to compute the average using numpy:
def funk(y1):
return np.mean(y1)

Related

Issue with vectorization in python

I have an application where I need to merge two solutions obtained from the scipy.integrate.solve_ivp in python. The actual application is a bit more complicated, but the following example shows the idea:
from scipy.integrate import solve_ivp import numpy as np
def lotkavolterra(t, z, a, b, c, d):
x, y = z
return [a*x - b*x*y, -c*y + d*x*y]
sol_1 = solve_ivp(lotkavolterra, [0, 10], [10, 5], args=(1.5, 1, 3, 1), dense_output=True).sol
sol_2 = solve_ivp(lotkavolterra, [10, 15], [10, 5], args=(1.5, 1, 3, 1), dense_output=True).sol
def sol_comb(t):
if t <= 10:
return sol_1(t)
else:
return sol_2(t)
I want to be able to use the merged or combined solution sol_comb on numpy arrays. Hence I tried to define a vectorized solution as follows:
sol_comb_vect = np.vectorize(sol_comb)
The following code, where I only call the functions on scalars, works fine:
print("sol_1 for t = 2",sol_1(2))
print("sol_2 for t = 11",sol_2(11))
print("sol_comb for t = 11",sol_comb(11))
print("sol_comb_vect for t = 11",sol_comb_vect(11))
The individual solutions sol_1 and sol_2 are apparently vectorized, since the following works fine:
print("sol_1 for t = [2,3]",sol_1(np.array([2])))
print("sol_2 for t = [11,13]",sol_2(np.array([11,13])))
However, if I call the non-vectorized function sol_comb on an array, as in the following example, I get the expected ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all():
print("sol_comb for t = [11,13]",sol_comb(np.array([11,13])))
I was expecting the vectorized version sol_comb_vect to work. However, in the following, I get the error ValueError: setting an array element with a sequence.
print("sol_comb_vect for t = [11,13]",sol_comb_vect(np.array([11,13])))
Any ideas how to fix this?
I would also be happy to merge the two OdeSolution instances in a cleaner way. In principle I think this should be possible, by using the time values and interpolants for sol_1 and sol_2, respectively.
I think you need to specify the signature for your output when you vectorize your function since by default the pyfunc you pass to np.vectorize() is assumed to take scalars as input and output see doc. And I assume that your ValueError is caused by that. So try this:
sol_comb_vect = np.vectorize(sol_comb, signature='()->(n)')
sol_comb_vect(np.array([2, 11, 13]))
output:
array([[0.60031288, 0.09618044],
[0.21298705, 1.36999868],
[2.58274789, 0.01857732]])
I don't know if this is the expected output tho. I hope this answers your question.

Dynamically adding functions to array columns

I'm trying to dynamically add function calls to fill in array columns. I will be accessing the array millions of times so it needs to be quick.
I'm thinking to add the call of a function into a dictionary by using a string variable
numpy_array[row,column] = dict[key[index containing function call]]
The full scope of the code I'm working with is too large to post here is an equivalent simplistic example I've tried.
def hello(input):
return input
dict1 = {}
#another function returns the name and ID values
name = 'hello'
ID = 0
dict1["hi"] = globals()[name](ID)
print (dict1)
but it literally activates the function when using
globals()[name](ID)
instead of copy pasting hello(0) as a variable into the dictionary.
I'm a bit out of my depth here.
What is the proper way to implement this?
Is there a more efficient way to do this than reading into a dictionary on every call of
numpy_array[row,column] = dict[key[index containing function call]]
as I will be accessing and updating it millions of times.
I don't know if the dictionary is called every time the array is written to or if the location of the column is already saved into cache.
Would appreciate the help.
edit
Ultimately what I'm trying to do is initialize some arrays, dictionaries, and values with a function
def initialize(*args):
create arrays and dictionaries
assign values to global and local variables, arrays, dictionaries
Each time the initialize() function is used it creates a new set of variables (names, values, ect) that direct to a different function with a different set of variables.
I have an numpy array which I want to store information from the function and associated values created from the initialize() function.
So in other words, in the above example hello(0), the name of the function, it's value, and some other things as set up within initialize()
What I'm trying to do is add the function with these settings to the numpy array as a new column before I run the main program.
So as another example. If I was setting up hello() (and hello() was a complex function) and when I used initialize() it might give me a value of 1 for hello(1).
Then if I use initialize again it might give me a value of 2 for hello(2).
If I used it one more time it might give the value 0 for the function goodbye(0).
So in this scenaro let's say I have an array
array[row,0] = stuff()
array[row,1] = things()
array[row,2] = more_stuff()
array[row,3] = more_things()
Now I want it to look like
array[row,0] = stuff()
array[row,1] = things()
array[row,2] = more_stuff()
array[row,3] = more_things()
array[row,4] = hello(1)
array[row,5] = hello(2)
array[row,6] = goodbye(0)
As a third, example.
def function1():
do something
def function2():
do something
def function3():
do something
numpy_array(size)
initialize():
do some stuff
then add function1(23) to the next column in numpy_array
initialize():
do some stuff
then add function2(5) to the next column in numpy_array
initialize():
do some stuff
then add function3(50) to the next column in numpy_array
So as you can see. I need to permanently append new columns to the array and feed the new columns with the function/value as directed by the initialize() function without manual intervention.
So fundamentally I need to figure out how to assign syntax to an array column based upon a string value without activating the syntax on assignment.
edit #2
I guess my explanations weren't clear enough.
Here is another way to look at it.
I'm trying to dynamically assign functions to an additional column in a numpy array based upon the output of a function.
The functions added to the array column will be used to fill the array millions of times with data.
The functions added to the array can be various different function with various different input values and the amount of functions added can vary.
I've tried assigning the functions to a dictionary using exec(), eval(), and globals() but when using these during assignment it just instantly activates the functions instead of assigning them.
numpy_array = np.array((1,5))
def some_function():
do some stuff
return ('other_function(15)')
#somehow add 'other_function(15)' to the array column.
numpy_array([1,6] = other_function(15)
The functions returned by some_function() may or may not exist each time the program is run so the functions added to the array are also dynamic.
I'm not sure this is what the OP is after, but here is a way to make an indirection of functions by name:
def make_fun_dict():
magic = 17
def foo(x):
return x + magic
def bar(x):
return 2 * x + 1
def hello(x):
return x**2
return {k: f for k, f in locals().items() if hasattr(f, '__name__')}
mydict = make_fun_dict()
>>> mydict
{'foo': <function __main__.make_fun_dict.<locals>.foo(x)>,
'bar': <function __main__.make_fun_dict.<locals>.bar(x)>,
'hello': <function __main__.make_fun_dict.<locals>.hello(x)>}
>>> mydict['foo'](0)
17
Example usage:
x = np.arange(5, dtype=int)
names = ['foo', 'bar', 'hello', 'foo', 'hello']
>>> np.array([mydict[name](v) for name, v in zip(names, x)])
array([17, 3, 4, 20, 16])

Store the return of a function in variable

I'm learning python, and I'm having trouble saving the return of a function to a specific variable. I have computed a simple function 'average' that is supposed to return the average value of a list. This works fine, however, when I try to store the result of average in a variable, I get told that x isn't defined.
def average(x):
return sum(x)/len(x)
var=average(x)
How do I store the return of the function in a variable?
Edit:
I misunderstood the task, which was simply to store the results of a specific computation in a variable.
x indeed is not defined
def average(x):
return sum(x)/len(x)
x = [1,2,3] # this was missing
var=average(x)
https://repl.it/join/eldrjqcr-datamafia
The function is a black box. You made the black box expect one mandatory input (x), therefore you have to provide it first i.e. var = average([1, 2, 3]).
Read the error message, x isn't defined. The variable x exists only in the average function and not in the program. You need to set x to something first.
e.g.
def average(x):
return sum(x)/len(x)
x=[1,2,3]
var=average(x)
this will not cause an error

Accessing objects and tuples from a function

I have a feeling there should be a very easy way to access specific elements from an evaluated function. A very simple example of what I am trying to achieve is
def func(x):
a = 2*x
b = x*x
return 1, 10, 100, (a,b)
I define a value for x and the function returns a set of values and a tuple. I would like to retrieve (for example) the first element and the tuple. Code such as
hello, cello = func(2)[[0,3]]
Returns an error. However I can access these elements individually,
bello = func(2)[3]
for example.
The function I am using takes a while to evaluate so making it run twice is not a desirable option. Furthermore, if possible I would not like to create a pile of variables for each individual element of the tuple (contains many).
In essence I would like a solution that is along the lines of:
hello, cello = func(2)[[0,3]]
Where,
hello = 1
cello = (4,4)
Thanks
So you can unpack and ignore:
hello, _, _, cello = func(2)
But if the result is more complicated you can use operator.itemgetter:
from operator import itemgetter
hello, cello, bello = itemgetter(0, 3, 15)(func(2))
Or more verbosely:
my_results = itemgetter(0, 3, 15)
hello, cello, bello = my_results(func(2))
Try
hello, cello = [func(2)[i] for i in [0,3]]
The standard solution would be to pack the returns into a dictionary and use that to separate the results.
In that way you save yourself the counting of the _ and the code is more readable
return {iteration: iter, Result: res....}
Erg=func(....)
And use
Erg[iteration]
later on.

Passing a well formulated criteria as a first class object in Python to an inner np.where() call?

How can I make this a dynamic or first class function that essentially passes the criteria to a np.where() call?
def num_assets(obj, criteria=None):
"""
A flexible wrapper to return the number of assets in a portfolio.
# list (asset names or characteristics)
>>> num_assets([1, 2, 3, 4, 5])
5
# number (pre-specification)
>>> num_assets(7)
7
# column vector (weights)
>>> num_assets(np.zeros(shape=(3,1)))
3
# matrix (covariance matrix)
>>> num_assets(np.eye(10))
10
# criteria.
>>> num_assets([1, 2, 3, 4, 5], '> 3')
??? I AM STUCK HERE AND NEED SOME HELP! Should return 2
"""
if criteria is None:
if myc.is_iterable(obj):
shape_obj = np.shape(obj)
return max(shape_obj)
elif myc.is_number(obj):
return myc.is_number(obj, True)
else:
return np.where(criteria)
myc.is_iterable() is essentially a boolean function containing a try except clause to iter notifying me if obj is iterable. myc.is_number() is telling me whether the obj is a number and when I pass the True parameter, it parses the number (in case obj is a string). I consider myself a newbie and know that this should not be too difficult a problem to solve, its just that I am not sure what advanced area of Python I need to apply to solve the criteria type problem (first class objects, meta programming, ...)? Also, if there is a cleaner more pythonic way of formulating the problem/getting the answer, contributions would be most welcome.
Thanks.
If I understand what you mean correctly, then I think this will do what you want.
if criteria is None:
what you already have
else:
obj = np.asarray(obj)
return np.sum(eval('obj'+criteria))
Its not elegant to have to use eval, but I think that's the easiest way to do this. For your example of criteria='>3', this becomes np.sum(obj>3), which is np.sum([False,False,False,True,True]), which is 2. where is not needed here.

Categories

Resources