Let's use the example on xlwings documentation.
Given the following python code:
import numpy as np
from xlwings import Workbook, Range
def rand_numbers():
""" produces std. normally distributed random numbers with shape (n,n)"""
wb = Workbook.caller() # Creates a reference to the calling Excel file
n = int(Range('Sheet1', 'B1').value) # Write desired dimensions into Cell B1
rand_num = np.random.randn(n, n)
Range('Sheet1', 'C3').value = rand_num
This is the original example.
Let's say we modify it slightly to be:
import numpy as np
from xlwings import Workbook, Range
def rand_numbers():
""" produces std. normally distributed random numbers with shape (n,n)"""
wb = Workbook.caller() # Creates a reference to the calling Excel file
n = int(Range('Sheet1', 'B1').value) # Write desired dimensions into Cell B1
rand_num = np.random.randn(n, n)
return rand_num #modified line
And we call it from VBA using the following call:
Sub MyMacro()
dim z 'new line'
z = RunPython ("import mymodule; mymodule.rand_numbers()")
End Sub
We get z as an empty value.
Is there any way to return a value to vba directly without writing to a text file, or putting the value first in the excel document?
Thank you for any pointers.
RunPython does not allow you to return values as per xlwings documentation.
To overcome these issue, use UDFs, see VBA: User Defined Functions (UDFs) - however, this is currently limited to Windows only.
https://docs.xlwings.org/en/stable/udfs.html#udfs
Related
Consider the following function in numba, which just serves as an example:
import numba as nb
import numpy as np
#nb.njit('float64(float64[::1])', cache=True)
def total (x):
''' Sum the elements of an array. '''
total = 0
for i in range(x.shape[0]):
total += x[i]
return total
x = np.arange(100,dtype=np.float64)
print(total(x))
Since I have specified the cache=True option, two files are created in the __pycache__ folder, one .nbc file and one .nbi file. I assume that these files contain all (compiled) information about the function. Let's say I delete the Python file that defines the function (i..e, the above code).
Can I still use compiled/cached functions? In other words, can I import them without having the original .py file that defined them?
#Michael Szczesny's comment about ahead of time compilation is exactly what I wanted. To make it work, I have adapted the code as follows:
from numba.pycc import CC
cc = CC('my_module')
#cc.export('total', 'float64(float64[::1])')
def total (x):
''' Sum the elements of an array. '''
total = 0
for i in range(x.shape[0]):
total += x[i]
return total
if __name__ == "__main__":
cc.compile()
After running this file, a binary module file (.pyd) is saved in the directory and you can use it as follows:
import numpy as np
from my_module import total
x = np.arange(100,dtype=np.float64)
print(total(x))
I want to use numpy.savez inside a loop so that I can directly save the array inside a file and save ram memory as I am dealing with huge data sets. Each iteration perfroms some work on the arrays, My idea is to stack the resulting array from each iteration on to previous arrays inside the npz file.
import numpy as np
a= [2,3,4]
b= [5,6,7]
steps=10
for n in range(steps):
a=a*3
b=b*4
np.savez('filename.npz', a=a, b=b)
But when I load the file, only the arrays from the last iteration is available. I know that the file is getting overwritten in each iteration, but is there a way I can stack all arrays inside the file?
You could do the following:
import numpy as np
a = np.array([2,3,4])
b = np.array([5,6,7])
steps = 10
Then, in order to save a different file with each iteration (inside the loop), you use format:
for i in range(steps):
a = a * 3
b = b * 3
np.savez('filename{:03}.npz'.format(i), a=a, b=b)
To load:
data = np.load('filename009.npz')
print(data['a']) # [118098 177147 236196]
print(data['b']) # [295245 354294 413343]
data2 = np.load('filename004.npz')
print(data2['b']) # [1215 1458 1701]
print(data2['a']) # [486 729 972]
You could even use something as crazy as timestamps!
from datetime import datetime
for _ in range(steps):
a = a * 3
b = b * 3
np.savez('filename-{}.npz'.format(datetime.now().isoformat(sep='_', timespec='auto')), a=a, b=b)
The result is:
filename-2020-01-24_00:02:42.013775.npz filename-2020-01-24_00:02:42.017066.npz
filename-2020-01-24_00:02:42.014601.npz filename-2020-01-24_00:02:42.017710.npz
filename-2020-01-24_00:02:42.015249.npz filename-2020-01-24_00:02:42.018611.npz
filename-2020-01-24_00:02:42.015946.npz filename-2020-01-24_00:02:42.019326.npz
filename-2020-01-24_00:02:42.016516.npz filename-2020-01-24_00:02:42.019864.npz
Since a couple of hours, I am trying to print a simple time vector in a txt file using Python.
import numpy as np
Tp = 2000 * 10**(-9)
dt = Tp / (90000)
t = np.linspace(0,Tp,dt)
timing = open("time.txt","w")
for ii in range(len(t)) :
timing.write(str(t[ii]))
timing.write("\n")
timing.close()
But I still get an empty file and I don't understand at all why.
Maybe I have to be more specific in the function with the precision I want.
Since I have a lot of small numbers (4e-10 ..) to process I would like to understand a general method to write variable (not the entire vector at once) on a txt file with a exponential notation (In Matlab it's kind of automatic I think).
Thx
You have an error using linspace. Please check https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html
Try this:
import numpy as np
Tp = 2000 * 10**(-9)
# dt = Tp / 90000.0
dt = 90000
t = np.linspace(0,Tp,dt)
timing = open("time.txt","w")
for ii in range(len(t)) :
timing.write(str(t[ii]))
timing.write("\n")
timing.close()
so I'm calling a python script from my Excel file with VBA and the ExcelPython reference. The python script is working fine except for Excel keeps telling me I have a type mismatch on the noted line:
Function calcCapValue(times As Range, fRates As Range, strike As Range, vol As Range, delta As Double, pv As Range) As Variant
Set methods = PyModule("PyFunctions", AddPath:=ThisWorkbook.Path)
Set result = PyCall(methods, "CalculateCapValue", KwArgs:=PyDict("times", times.Value2, "fwdRates", fRates.Value2, "strike", strike.Cells(1, 1).Value2, "flatVol", vol.Cells(1, 1).Value2, "delta", delta, "pv", pv.Cells(1, 1).Value2))
calcCapValue = PyVar(PyGetItem(result, "res")) ' <--- TYPE MISMATCH HERE
Exit Function
End Function
Can't figure out why, I'm following the example code from here: https://sourceforge.net/p/excelpython/wiki/Putting%20it%20all%20together/
and here: http://www.codeproject.com/Articles/639887/Calling-Python-code-from-Excel-with-ExcelPython
Still getting this type mismatch and I can't figure out why.
Here's the python script:
#imports
import numpy as np
from scipy.stats import norm
#
# Cap Price Calculation
#
def CalculateCapValue(times, fwdRates, strike, flatVol, delta, pv):
capPrice = 0;
#Iterate through each time for caplet price
for i in range(0, len(times)):
ifr = float(fwdRates[i][0])
iti = float(times[i][0])
d1 = (np.log(ifr/strike)+((flatVol**2)*iti)/2)/(flatVol*np.sqrt(iti))
d2 = d1 - (flatVol*np.sqrt(iti))
Nd1 = norm.cdf(d1)
Nd2 = norm.cdf(d2)
capPrice += pv*delta*(ifr*Nd1 - strike*Nd2)
return {"res": capPrice}
Thanks!
Question answered on ExcelPython discussion forums on Sourceforge:
http://sourceforge.net/p/excelpython/discussion/general/thread/97f6c1b0/
I want to calculate the sumproduct of two arrays in Theano. Both arrays are declared as shared variables and are the result of prior computations. Reading the tutorial, I found out how to use scan to compute what I want using 'normal' tensor arrays, but when I tried to adapt the code to shared arrays I got the error message TypeError: function() takes at least 1 argument (1 given). (See minimal running code example below)
Where is the mistake in my code? Where is my misconception? I am also open to a different approach for solving my problem.
Generally I would prefer a version which takes the shared variables directly, because in my understanding, converting the arrays first back to Numpy arrays and than again passing them to Theano, would be wasteful.
Error message producing sumproduct code using shared variables:
import theano
import theano.tensor as T
import numpy
a1 = [1,2,4]
a2 = [3,4,5]
Ta1_shared = theano.shared(numpy.array(a1))
Ta2_shared = theano.shared(numpy.array(a2))
outputs_info = T.as_tensor_variable(numpy.asarray(0, 'float64'))
Tsumprod_result, updates = theano.scan(fn=lambda Ta1_shared, Ta2_shared, prior_value:
prior_value + Ta1_shared * Ta2_shared,
outputs_info=outputs_info,
sequences=[Ta1_shared, Ta2_shared])
Tsumprod_result = Tsumprod_result[-1]
Tsumprod = theano.function(outputs=Tsumprod_result)
print Tsumprod()
Error message:
TypeError: function() takes at least 1 argument (1 given)
Working sumproduct code using non-shared variables:
import theano
import theano.tensor as T
import numpy
a1 = [1, 2, 4]
a2 = [3, 4, 5]
Ta1 = theano.tensor.vector("a1")
Ta2 = theano.tensor.vector("coefficients")
outputs_info = T.as_tensor_variable(numpy.asarray(0, 'float64'))
Tsumprod_result, updates = theano.scan(fn=lambda Ta1, Ta2, prior_value:
prior_value + Ta1 * Ta2,
outputs_info=outputs_info,
sequences=[Ta1, Ta2])
Tsumprod_result = Tsumprod_result[-1]
Tsumprod = theano.function(inputs=[Ta1, Ta2], outputs=Tsumprod_result)
print Tsumprod(a1, a2)
You need to change the compilation line to this one:
Tsumprod = theano.function([], outputs=Tsumprod_result)
theano.function() always need a list of inputs. If the function take 0 input, like in this case, you need to give an empty list for the inputs.