
Is there some way to get the equivalent of repmat() for ndim == 1 and ndim >2. For ndim == 1, repmat always returns a 2-d array, instead of remaining 1-d. For ndim >2, repmat just doesn't work.
Maybe we could add a 'reparray', with the signature: reparray(A, repeats, axis=None) where repeats is a scalar or a sequence. If 'repeats' is a scalar then the matrix is duplicated along 'axis' that many times. If 'repeats' is a sequence of length N, then A is duplicated repeats[i] times along axis[i]. If axis is None then it is assumed to be (0,1,2...N).
Er that's not quite complete, because it doesn't specify what happens when you reparray an array to a higher dimension, like a 1-d to a 3-d. Like reparray([1,2], (2,2,2)). I guess the axis parameter could have some 'newaxis' entries to accomodate that.
--bb

Ok, here's my best shot at a generalized repmat:
def reparray(A, tup): if numpy.isscalar(tup): tup = (tup,) d = len(tup) A = numpy.array(A,copy=False,subok=True,ndmin=d) for i,k in enumerate(tup): A = numpy.concatenate([A]*k, axis=i) return A
Can anyone improve on this? The only way I could think to seriously improve it would be if there were an N-way concatenate() function in the C-API. Each call to concatenate() involves a potentially big allocation and memcpy of the data.
And here's a docstring for it: """Repeat an array the number of times given in the integer tuple, tup.
Similar to repmat, but works for arrays of any dimension. reparray(A,(m,n)) is equivalent to repmat(A,m,n)
If tup has length d, the result will have dimension of max(d, A.ndim). If tup is scalar it is treated as a 1-tuple.
If A.ndim < d, A is promoted to be d-dimensional by prepending new axes. So a shape (3,) array is promoted to (1,3) for 2-D replication, or shape (1,1,3) for 3-D replication. If this is not the desired behavior, promote A to d-dimensions manually before calling this function.
If d < A.ndim, ndim is effectively promoted to A.ndim by appending 1's to tup.
Examples: >>> a = array([0,1,2]) >>> reparray(a,2) array([0, 1, 2, 0, 1, 2]) >>> reparray(a,(1,2)) array([[0, 1, 2, 0, 1, 2]]) >>> reparray(a,(2,2)) array([[0, 1, 2, 0, 1, 2], [0, 1, 2, 0, 1, 2]]) >>> reparray(a,(2,1,2)) array([[[0, 1, 2, 0, 1, 2]],
[[0, 1, 2, 0, 1, 2]]])
See Also: repmat, repeat """

On Fri, 22 Sep 2006, Bill Baxter apparently wrote:
Ok, here's my best shot at a generalized repmat:
Sorry to always repeat this suggestion when it comes to repmat, but I think the whole approach is wrong. A repmat should be a separate object type, which behaves like the described matrix but has only one copy of the repetitive data.
Cheers, Alan Isaac

On 9/22/06, Alan G Isaac aisaac@american.edu wrote:
On Fri, 22 Sep 2006, Bill Baxter apparently wrote:
Ok, here's my best shot at a generalized repmat:
Sorry to always repeat this suggestion when it comes to repmat, but I think the whole approach is wrong. A repmat should be a separate object type, which behaves like the described matrix but has only one copy of the repetitive data.
That may be true for some cases. But I usually start modifying the data I create right after a repmat. It wouldn't help in that case. So unless you're really making a lot of large repmats of arrays that never change, or for use as temp variables, I can't see a separate class being that much of a win, compared with the complexity of implementing and maintaining it (think "fancy indexing"). YMMV. However, repmat seems to be far less commonly needed in numpy than in Matlab. I think that's mostly thanks to the broadcasting rules, which already create a sort of implicit repmat of the input in many common cases.
--bb

Here's a new version of 'reparray'.
I tested the previous version against 'repmat' for the 2d case and found it to be as much as 3x slower in some instances. Ick. So I redid it using the approach repmat uses -- reshape() and repeat() rather than concatenate(). Now it's very nearly as fast as repmat for the 2-d case.
def reparray(A, tup): if numpy.isscalar(tup): tup = (tup,) d = len(tup) c = numpy.array(A,copy=False,subok=True,ndmin=d) shape = list(c.shape) n = c.size for i, nrep in enumerate(tup): if nrep!=1: c = c.reshape(-1,n).repeat(nrep,0) dim_in = shape[i] dim_out = dim_in*nrep shape[i] = dim_out n /= dim_in return c.reshape(shape)
The full file with tests and timing code is attached.
One thing I noticed while doing this was that repmat doesn't preserve subclasses. Which is funny considering 'mat' is part of the name and it only works on 2-d arrays. Using asanyarray() instead of asarray() in the first line should fix that.
--Bill
participants (2)
-
Alan G Isaac
-
Bill Baxter