Reputation: 1165
I m looking to return a matrix that is the average of the consecutive columns of another matrix, however the first column is the average between 1 and the first column of the input matrix.
I was able to achieve it by the following code but i believe this is not the most efficient way to deal with this problem.
import numpy as np
a = np.matrix([[ 0.6,1.2,1.8,2.4,3],[0.8,1.6,2.4,3.2,4]])
matrix_resultado = numpy.zeros(shape=a.shape) #Same shape resulting matrix
matrix_resultado[:,[0]] = ((1+a[:,0])/2) #First column average
#loop to calculate the average between the columns
for n in range(1,5):
matrix_resultado[:,[n]] = ((a[:,(n-1)]+a[:,n])/2)
matrix_resultado
array([[ 0.8, 0.9, 1.5, 2.1, 2.7],
[ 0.9, 1.2, 2. , 2.8, 3.6]])
What is the most efficient way to achieve the same result ?
Upvotes: 0
Views: 162
Reputation: 221614
Approach #1 : Here's one approach -
In [14]: col0_avg = (a[:,0,None] + 1)/2
In [15]: avg = (a[:,1:] + a[:,:-1])/2
In [16]: np.c_[col0_avg, avg]
Out[16]:
matrix([[ 0.8, 0.9, 1.5, 2.1, 2.7],
[ 0.9, 1.2, 2. , 2.8, 3.6]])
Approach #1-S : To avoid the concatenation, we can start off with the input array and then perform those averaging steps in-place, like so -
out = a.copy()
out[:,1:] += a[:,:-1]
out[:,0] += 1
out /= 2
Approach #2 : Probably faster using uniform-filter
-
In [35]: from scipy.ndimage.filters import uniform_filter1d as unif1d
In [150]: unif1d(a,size=2, axis=1, mode='constant', cval=1.0)
Out[150]:
array([[ 0.8, 0.9, 1.5, 2.1, 2.7],
[ 0.9, 1.2, 2. , 2.8, 3.6]])
Runtime test -
In [133]: a = np.asmatrix(np.random.randn(200,10000))
In [134]: %%timeit
...: col0_avg = (a[:,0,None] + 1)/2
...: avg = (a[:,1:] + a[:,:-1])/2
...: out0 = np.c_[col0_avg, avg]
100 loops, best of 3: 7.3 ms per loop
In [135]: %%timeit
...: out = a.copy()
...: out[:,1:] += a[:,:-1]
...: out[:,0] += 1
...: out /= 2
100 loops, best of 3: 5.22 ms per loop
In [152]: %timeit unif1d(a,size=2, axis=1, mode='constant', cval=1.0)
100 loops, best of 3: 6.71 ms per loop
Upvotes: 3