I have created a small Python program to multiply two 2 by 2 matrices but am wondering if it could be simplified in any way (particularly the creation of new arrays)
The python code is below:
matA=[0]*2
matB=[0]*2
matC=[0]*2
matC[0]=[0]*2
matC[1]=[0]*2
# creating new arrays for multiplying two 2 by 2 matrices
# must be a more simple way
def multiply2by2matrices(a,b):
matC[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]
matC[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1]
matC[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0]
matC[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1]
print ((matC[0][0]),(matC[0][1]))
print ((matC[1][0]),(matC[1][1]))
matA[0]=[4,3]
matA[1]=[2,12]
matB[0]=[5,-2]
matB[1]=[6,3]
multiply2by2matrices(matA, matB)
Any thoughts will be greatly received.
Don't implement by hand. You are reinventing the wheel and there very good wheels around already.
Numpy is the answer.
import numpy as np
a = np.arange(20).reshape(5,4)
b = (np.arange(20) + 10).reshape(4,5)
np.dot(a,b)
Docs:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html
Cheers, P
Unless you are required to use only vanilla python it would be much simpler to use numpy. You can use the matrix class or just use 2d arrays and the dot function. For example:
import numpy as np
a=np.array([[1,1],[2,2]])
b=np.array([[3,3],[3,3]])
c=np.dot(a,b)
produces:
array([[ 6, 6],
[12, 12]])
You can definitely simplify matrix multiplication and make it general. The trick is to use zip. There are other methods of course, but I think zip might produce some of the cleaner code.
I didn't test the following, but I think my linear algebra serves me right.
def matmult(a,b):
zipb = zip(*b)
return [[sum(ax*bx for ax,bx in zip(rowa, colb)) for colb in zipb] for rowa in a]
If you don't use a list comprehension you're going to need to pre-allocate a list or use append/extend in between for loops.
Related
For instance, in Julia language, a function can easily be vectorized as shown
function circumference_of_circle(r)
return 2*π * r
end
a = collect([i for i=1:200])
circumference_of_circle.(a) # easy vactorization using just (.)
Although I like Julia very much, it has not matured like Python.
Is there a similar vectorization technique in the Python function?
In [1]: def foo(r):
...: return 2*np.pi * r
...:
In [2]: arr = np.arange(5)
In [3]: foo(arr)
Out[3]: array([ 0. , 6.28318531, 12.56637061, 18.84955592, 25.13274123])
All operations in your function work with numpy arrays. There's no need to do anything special.
If your function only works with scalar arguments, "vectorizing" becomes trickier, especially if you are seeking compiled performance.
Have you spent much time reading the numpy basics? https://numpy.org/doc/stable/user/absolute_beginners.html
===
I don't know julia, but this code
function _collect(::Type{T}, itr, isz::SizeUnknown) where T
a = Vector{T}()
for x in itr
push!(a, x)
end
return a
end
looks a lot like
def foo(func, arr):
alist = []
for i in arr:
alist.append(func(i))
return alist # or np.array(alist)
or equivalently the list comprehension proposed in the other answer.
or list(map(func, arr))
I'm not familiar with Julia or vectorization of functions, but if I'm understanding correctly, I believe in Python there are a few ways to do this. The plain-jane python way is using list comprehension
An example using your circumference function would be:
def circumference_of_circle(r):
return 2 * 3.14152 * r
circles = [[x, circumference_of_circle(x)] for x in range(1,201)]
print(circles)
circles list will contain inner lists that have both the radius (generated by the range() function) as well as its circumference. Like Julia function vectorization, python list comprehension is just short-hand for loops, but they take in a list object and return a list object, so they are very handy.
Your function contains only simple math. Python's numpy and pandas modules are designed in ways that allow such operations to be performed on them.
import numpy as np
a = np.array([1,2,3,4])
def circumference_of_circle(r):
return 2 * np.pi * r
print(circumference_of_circle(a)) # array([ 6.28318531, 12.56637061, 18.84955592, 25.13274123])
More complicated functions cannot be applied directly to an array. You may be able to rewrite the function in a vectorized way, for example using np.where for conditions that would be represented by an if block within a normal function.
If this isn't an option, or speed is not a major concern, then you can iterate over the list using a list comprehension [func(v) for v in arr], numpy's vectorize, pandas's apply. You can sometimes optimize these approaches by pre-compiling parts of the code.
I have two numpy arrays, one is 2D of dimension (a, b) and the other is 1D of dimension a. I want to add the single value for each index of the 1D array to each member of the same index in the 2D array. Here's an example of what I'm trying to do:
import numpy as np
firstArr = np.random.random((5,6))
secondArr = np.linspace(0, 4, 5)
I know I can do what I want with the loop:
for i in range(5):
firstArr[i] = firstArr[i] + secondArr[i]
But this is really not Pythonic, so it will no doubt take a looong time when I do it over millions of iterations.
What's the solution, here? Thanks!
Edit:
I think I found the answer: use np.newaxis. This works, but I don't know if there's a more efficient way to do this. Here's how It would work:
arr = firstArr + secondArr[:, np.newaxis]
I'm leaving the question open for now because there's probably a more efficient way of doing this, but this at least works. It can also, per Numpy documentation, be written as:
arr = firstArr + secondArr[:, None]
I'll admit I don't know what exactly this does (still looking into that), so any guidance would be appreciated
Is there a faster way to populate a 2d numpy array using the same algorithm (pnoise3 with the same input arguments, notably, i/scale j/scale) seen here? self.world is the np array and it is pretty large (2048,1024) to be traversing like this.
for i in range(self.height):
for j in range(self.width):
self.world[i][j] = noise.pnoise3(i/self.noise['scale'],
j/self.noise['scale'],
SEED,
octaves = self.noise['octaves'],
persistence = self.noise['persistence'],
lacunarity = self.noise['lacunarity'],
repeatx= self.width,
repeaty= self.height,
base= 0)
After learning about boolean indexing I was able to get rid of this nested for loop elsewhere in my program and was amazed at how much more efficient it was. Is there any room for improvement above?
I thought about doing something like self.world[self.world is not None] = noise.pnoise3(arg, arg, etc...) but that cannot accommodate for the incrementing i and j values. And would setting it to a function output mean every value is the same anyways? I also thought about make a separate array and then combining them but I still cannot figure out how to reproduce the incrementing i and j values in that scenario.
Also, as an aside, I used self.world[self.world is not None] as an example of a boolean index that would return true for everything but I imagine this is not the best way to do what I want. Is there an obvious alternative I am missing?
If pnoise is perlin noise then there are numpy vectorized implementations.
Here is one.
As it is I do not think you can do it faster. Numpy is fast when it can do the inner loop in C. That is the case for built in numpy functions like np.sin.
Here you have a vector operation where the operation is a python function.
However it could be possible to re-implement the noise function so that it internally uses numpy vectorized functions.
I couldn't seem to find this problem on stackoverflow although I'm sure someone has asked this before.
I have two numpy arrays as follows:
a = np.ones(shape = (2,10))
b = np.ones(2)
I want to multiply the first row of 10 of a by the first number in b and the second row by the second number. I can do this using lists as follows:
np.array([x*y for x,y in zip(b,a)])
I was wondering if there is a way to do this in numpy that would be a similar one liner to the list method.
I am aware I can reshape a to (1,2,10) and b to (2,1) to effectively achieve this - is this the only solution? Or is there a numpy method that can do this without manually reshaping.
This might be what you are looking for:
a*np.tile(np.expand_dims(b,axis=1),(1,10))
If you want to make use of the automatic numpy broadcasting, you need to reshape b first:
np.multiply(a, b.reshape(2,1))
I work with Python 2.7, numpy and pandas.
I have :
a function y=f(x) where both x and y are scalars.
a one-dimensional array of scalars of length n : [x0, x1, ..., x(n-1)]
I need to construct a 2-dimensional array D[i,j]=f(xi)*f(xj) where i,j are indices in [0,...,n-1].
I could use loops and/or a comprehension list, but that would be slow. I would like to use a vectorized approach instead.
I thought that "numpy.indices" would help me (see Create a numpy matrix with elements a function of indices), but I admit I am at a loss on how to use that command for my purpose.
Thanks in advance!
Ignore the comments that dismiss vectorization; it's a good habit to have, and it does deliver performance with the right accelerators. Anyway, what I really wanted to say was that you want to find the outer product:
x_ = numpy.array(x)
y = f(x_)
numpy.outer(y, y)
If you're working with numbers you should be working with numpy data structures anyway. Then you get fast, readable code like this.
I would like to use a vectorized approach instead.
You sound like you might be a Matlab user -- you should be aware that numpy's vectorize function provides no performance benefit:
The vectorize function is provided primarily for convenience, not for
performance. The implementation is essentially a for loop.
Unless it just so happens that there's already an operation in numpy that does exactly what you want, you're going to be stuck with numpy.vectorize and nothing to really gain over a for loop. With that being said, you should be able to do that like so:
def makeArray():
a = [1, 2, 3, 4]
def addTo(arr):
return f(a[math.floor(arr/4)]) * f(a[arr % 4])
vecAdd = numpy.vectorize(addTo)
return vecAdd(numpy.arange(4 * 4).reshape(4, 4))
EDIT:
If f is actually a one-dimensional array, you can do this:
f_matrix = numpy.matrix(f)
D = f_matrix.T * f_matrix
You can use fromfunc to vectorize the function then use the dot product to multiply:
f2 = numpy.fromfunc(f, 1, 1) # vectorize the function
res1 = f2(x) # get the results for f(x)
res1 = res1[np.newaxis] # result has to be 2D for the next step
res2 = np.dot(a.T, a) # get f(xi)*f(xj)