Creating a block array from a given array [duplicate] - python

This question already has answers here:
Quick way to upsample numpy array by nearest neighbor tiling [duplicate]
(3 answers)
Closed 2 years ago.
I have a 2d array like this
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
and I want to create an array, where every entry of the one above fills a whole block of the new array. I.e. if I want 2x2 blocks, I want my new array to look like this
B = np.array([[1, 1, 2, 2, 3, 3],
[1, 1, 2, 2, 3, 3],
[..., ..., ...,],
[..., 8, 8, 9, 9],
[..., 8, 8, 9, 9]])
I managed to do this by iterating over the arrays and creating a corresponding block for every entry, but I'm wondering if there's a better way to do this.

A.repeat(2, axis=1).repeat(2, axis=0)
First repeat the elements along the first axis to get:
array([[1, 1, 2, 2, 3, 3],
[4, 4, 5, 5, 6, 6],
[7, 7, 8, 8, 9, 9]])
Then repeat the elements along the zeroth axis to get:
array([[1, 1, 2, 2, 3, 3],
[1, 1, 2, 2, 3, 3],
[4, 4, 5, 5, 6, 6],
[4, 4, 5, 5, 6, 6],
[7, 7, 8, 8, 9, 9],
[7, 7, 8, 8, 9, 9]])
(The order of repetition axes doesn't matter.)
You can change 2s to the desired block size.

Related

Python - how to resize an array and duplicate the elements

I've got an array with data like this
a = [[1,2,3],[4,5,6],[7,8,9]]
and I want to change it to
b = [[1,1,2,2,3,3],[1,1,2,2,3,3],[4,4,5,5,6,6],[4,4,5,5,6,6],[7,7,8,8,9,9],[7,7,8,8,9,9]]
I've tried to use numpy.resize() function but after resizing, it gives [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]]. I can use a for loop to put the numbers at the indexes I need but just wondering if there is any easier way of doing that?
To visualise the task, here is the original array
This is what I want
My initial though was that np.tile would work but in fact what you are looking for is np.repeat twice on two different axes.
Try this runnable example!
#!/usr/bin/env python
import numpy as np
a = [[1,2,3],[4,5,6],[7,8,9]]
b = np.repeat(np.repeat(a, 2, axis=1), 2, axis=0)
b
<script src="https://modularizer.github.io/pyprez/pyprez.min.js"></script>
You can think of your problem as resizing each 1x1 block to a 2x2 block. This can simply be done using numpy.kron(a, b), which operates on each element of a – each 1x1 block – and "expands" it according to b – which should thus be a 2x2 block.
>>> import numpy as np
>>> a = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> np.kron(a, [[1, 1], [1, 1]])
array([[1, 1, 2, 2, 3, 3],
[1, 1, 2, 2, 3, 3],
[4, 4, 5, 5, 6, 6],
[4, 4, 5, 5, 6, 6],
[7, 7, 8, 8, 9, 9],
[7, 7, 8, 8, 9, 9]])
An efficient way to create the second operand for larger structures is using np.ones and related functions.
>>> np.kron(a, np.ones((2,4), dtype=int))
array([[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3],
[4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6],
[4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6],
[7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9],
[7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9]])

Creating shifted Hankel matrix

Say I have some time-series data in the form of a simple array.
X1 = np.array[(1, 2, 3, 4]
The Hankel matrix can be obtained by using scipy.linalg.hankel, which would look something like this:
hankel(X1)
array([[1, 2, 3, 4],
[2, 3, 4, 0],
[3, 4, 0, 0],
[4, 0, 0, 0]])
Now assume I had a larger array in the form of
X2 = np.array([1, 2, 3, 4, 5, 6, 7])
What I want to do is fill in the zeros in this matrix with the numbers that are next in the index (specific to each row). Taking the same Hankel matrix earlier by using the first four values in the array X2, I'd like to see the following output:
hankel(X2[:4])
array([[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 6],
[4, 5, 6, 7]])
How would I do this? I'd ideally like to use this for larger data.
Appreciate any tips or pointers given. Thanks!
If you have a matrix with the appropriate index values into your dataset, you can use integer array indexing directly into your dataset.
To create the index matrix, you can simply use the upper-left quadrant of a double-sized Hankel array. There are likely simpler ways to create the index matrix, but this does the trick.
>>> X = np.array([9, 8, 7, 6, 5, 4, 3])
>>> N = 4 # the size of the "window"
>>> indices = scipy.linalg.hankel(np.arange(N*2))[:N, :N]
>>> indices
array([[0, 1, 2, 3],
[1, 2, 3, 4],
[2, 3, 4, 5],
[3, 4, 5, 6]])
>>> X[indices]
array([[9, 8, 7, 6],
[8, 7, 6, 5],
[7, 6, 5, 4],
[6, 5, 4, 3]])

numpy.roll horizontally on a 2D ndarray with different values

Doing np.roll(a, 1, axis = 1) on:
a = np.array([
[6, 3, 9, 2, 3],
[1, 7, 8, 1, 2],
[5, 4, 2, 2, 4],
[3, 9, 7, 6, 5],
])
results in the correct:
array([
[3, 6, 3, 9, 2],
[2, 1, 7, 8, 1],
[4, 5, 4, 2, 2],
[5, 3, 9, 7, 6]
])
The documentation says:
If a tuple, then axis must be a tuple of the same size, and each of the given axes is shifted by the corresponding number.
Now I like to roll rows of a by different values, like [1,2,1,3] meaning, first row will be rolled by 1, second by 2, third by 1 and forth by 3. But np.roll(a, [1,2,1,3], axis=(1,1,1,1)) doesn't seem to do it. What would be the correct interpretation of the sentence in the docs?
By specifying a tuple in np.roll you can roll an array along various axes. For example, np.roll(a, (3,2), axis=(0,1)) will shift each element of a by 3 places along axis 0, and it will also shift each element by 2 places along axis 1. np.roll does not have an option to roll each row by a different amount. You can do it though for example as follows:
import numpy as np
a = np.array([
[6, 3, 9, 2, 3],
[1, 7, 8, 1, 2],
[5, 4, 2, 2, 4],
[3, 9, 7, 6, 5],
])
shifts = np.c_[[1,2,1,3]]
a[np.c_[:a.shape[0]], (np.r_[:a.shape[1]] - shifts) % a.shape[1]]
It gives:
array([[3, 6, 3, 9, 2],
[1, 2, 1, 7, 8],
[4, 5, 4, 2, 2],
[7, 6, 5, 3, 9]])

Create a list of list with flexible input (Python) [duplicate]

This question already has answers here:
How can I make a for-loop pyramid more concise in Python? [duplicate]
(4 answers)
Closed 5 years ago.
I currently have a function that creates a list of lists like below using 3 nested for-loops.
[[1,1,1] , [1,1,2] , .... , [3,3,3]]
However, the problem is I can't use this function if someone wants the list of list to be something like
[[1,1,1,1,1,1,1] , ..... , [9,9,9,9,9,9,9]]
which has more numbers (from 1 - 9) and more elements (7 of 1's instead of 4).
Here's my current code:
def listofList():
temp = []
for i in range(1,4):
for j in range(1,4):
for k in range(1,4):
temp.append([i,j,k])
return temp
Can someone provide me with a better solution? I want my function listofList() to be flexible where it could receive an input for both the size of the list of list and the elements inside the list.
Try the following:
def listofList(subLen, totalLen):
final = [[item for i in range(subLen)] for item in range(1, totalLen+1)]
return final
>>> listofList(9, 9)
[[1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2], [3, 3, 3, 3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4, 4, 4, 4], [5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9]]
>>> listofList(9, 2)
[[1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2]]
>>> listofList(2, 9)
[[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9]]
>>>

fill a one dimension space with predefined values [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I would like to fill a length with predefined "subLengths".
let say my subLength are : 3,4,5,6,7,10.
To fill a length of 15 I can use "10+5" , "3+4+3+5" ,"7+4+4" ,"7+5+3" ....
How could I get as an array one of theses results ?
Better : how could I get an array for several good results ? My maximum length is 70 and I guess It could be time consuming to get all the good results for this value.
I am a 3d artist, my coding skill is quiet limited and I just don't know how to deal with this problem .I can use Python or a language looking like C for that.
this code seems to work in my software :
def fillBuild(length, subLengths):
for i in range(len(subLengths)):
if subLengths[i] == length:
yield subLengths[i:i + 1]
elif subLengths[i] < length:
for subResult in fillBuild(length - subLengths[i] ,subLengths[i:] ):
yield subLengths[i:i + 1] + subResult
Recursive generator function (Python) producing all possible sublist permutations (with repetitions) of pool adding up to total:
from pprint import pprint
def sub_lists(pool, total):
for i in range(len(pool)):
if pool[i] == total:
yield pool[i:i + 1]
elif pool[i] < total:
for sub_list in sub_lists(pool, total - pool[i]):
yield pool[i:i + 1] + sub_list
pprint(list(sub_lists([3, 4, 5, 6, 7, 10], 15)))
[[3, 3, 3, 3, 3],
[3, 3, 3, 6],
[3, 3, 4, 5],
[3, 3, 5, 4],
[3, 3, 6, 3],
[3, 4, 3, 5],
[3, 4, 4, 4],
[3, 4, 5, 3],
[3, 5, 3, 4],
[3, 5, 4, 3],
[3, 5, 7],
[3, 6, 3, 3],
[3, 6, 6],
[3, 7, 5],
[4, 3, 3, 5],
[4, 3, 4, 4],
[4, 3, 5, 3],
[4, 4, 3, 4],
[4, 4, 4, 3],
[4, 4, 7],
[4, 5, 3, 3],
[4, 5, 6],
[4, 6, 5],
[4, 7, 4],
[5, 3, 3, 4],
[5, 3, 4, 3],
[5, 3, 7],
[5, 4, 3, 3],
[5, 4, 6],
[5, 5, 5],
[5, 6, 4],
[5, 7, 3],
[5, 10],
[6, 3, 3, 3],
[6, 3, 6],
[6, 4, 5],
[6, 5, 4],
[6, 6, 3],
[7, 3, 5],
[7, 4, 4],
[7, 5, 3],
[10, 5]]
Here's a recursive solution, using Python 2.7:
def fill(length, sublengths):
# IMPORTANT: this function will produce INCORRECT RESULTS if sublengths
# is not a list of unique integers sorted increasingly.
fillings = []
for i, sublength in enumerate(sublengths):
if sublength > length:
# if sublength is greater than length, there are no more allowable
# fillings (because sublengths are unique and are sorted
# increasingly), so we return the fillings collected so far;
return fillings
elif sublength == length:
# if sublength is exactly equal to length, then only one filling is
# possible, namely [sublength]; we append this filling to the
# fillings;
fillings.append([sublength])
else:
# we generate all the fillings that begin with sublength by
# prepending sublength to all the allowable fillings of
# (length - sublength), which we obtain by making a recursive call.
fillings.extend([[sublength] + subresult
for subresult in
fill(length - sublength, sublengths[i:])])
Example:
In [2]: fill(15, [3, 4, 5, 6, 7, 10])
Out[2]:
[[3, 3, 3, 3, 3],
[3, 3, 3, 6],
[3, 3, 4, 5],
[3, 4, 4, 4],
[3, 5, 7],
[3, 6, 6],
[4, 4, 7],
[4, 5, 6],
[5, 5, 5],
[5, 10]]
BTW: fill(70, [3, 4, 5, 6, 7, 10])) produces 1657 possible fillings, so you may want some additional criterion to whittle down the alternatives.
Some notes:
in order to avoid repeating solutions, we will require that each filling be ordered increasingly;
the key idea is this: suppose that the length to fill is L, and a1 < a2 < ... < an are the available sublengths. To find all the possible fillings of L that begin with a1 is tantamount to prepending a1 to all the fillings of L - a1. This is the rationale for the recursive call in the else block of fill. (When a function calls itself, as fill does, the function is said to be recursive.)
Since fill requires sublengths to be free of duplicates and sorted increasingly, we can use the following front-end function to ensure these conditions are satisfied:
def do_fill(length, sublengths):
return fill(length, sorted(set(sublengths)))
(NB: Below is a fairly detailed explanation of what the code does. If you already understand the code, you can safely skip the rest of this post.)
To better see what's going on, go back to the example above, and start by grouping the solutions according to the first sublength; you'll get the three groups shown below:
# group I
[3, 3, 3, 3, 3]
[3, 3, 3, 6]
[3, 3, 4, 5]
[3, 4, 4, 4]
[3, 5, 7]
[3, 6, 6]
# group II
[4, 4, 7]
[4, 5, 6]
# group III
[5, 5, 5]
[5, 10]
Now, compare the fillings in group I, all of which begin with 3, with the fillings for 15-3 = 12, using the sublengths [3, 4, 5, 6, 7, 10]:
In [3]: fill(15 - 3, [3, 4, 5, 6, 7, 10])
Out[3]:
[[3, 3, 3, 3],
[3, 3, 6],
[3, 4, 5],
[4, 4, 4],
[5, 7],
[6, 6]]
If now you prepend 3 to all these fillings, you'll get exactly the fillings in group I.
Now consider the fillings in group II, all of which begin with 4. Compare them with the fillings for 15 - 4 = 11, using the sublengths [4, 5, 6, 7, 10]:
In [4]: fill(15 - 4, [4, 5, 6, 7, 10])
Out[4]:
[4, 7],
[5, 6]
Again, if you prepend 4 to all these fillings you get exactly the fillings in group II.
You may wonder, why did I use [4, 5, 6, 7, 10] as the sublengths in the last call to fill above, and not [3, 4, 5, 6, 7, 10]? This is because I am interested only in fillings that are increasingly ordered and that begin with 4. This rules out any fillings that include 3.
Finally, to get the fillings in group III, prepend 5 to all the fillings for 15 - 5 = 10, using sublengths [5, 6, 7, 10]:
In [5]: fill(15 - 5, [5, 6, 7, 10])
Out[5]:
[[5, 5],
[10]]
If you are so inclined you can repeat the same sort of analysis for each of the subgroups. For example, you can group the fillings generated by fill(15 - 3, [3, 4, 5, 6, 7, 10]) according to their first element; you'd get 4 groups:
[3, 3, 3, 3]
[3, 3, 6]
[3, 4, 5]
[4, 4, 4]
[5, 7]
[6, 6]
These groups are obtained by prepending 3, 4, 5, or 6, respectively, to the fillings produced by
fill((15 - 3) - 3, [3, 4, 5, 6, 7, 10])
fill((15 - 3) - 4, [ 4, 5, 6, 7, 10])
fill((15 - 3) - 5, [ 5, 6, 7, 10])
fill((15 - 3) - 6, [ 6, 7, 10])
The analysis above just does "by hand" exactly what the fill function does.
One important thing to note is that, with every recursive call, the problem becomes simpler.
For example, in the process of generating filling [3, 5, 7] the following calls to fill got executed:
fill(15, [3, 4, 5, 6, 7, 10]) = fill(15, [3, 4, 5, 6, 7, 10])
fill(15 - 3, [3, 4, 5, 6, 7, 10]) = fill(12, [3, 4, 5, 6, 7, 10])
fill(15 - 3 - 5, [ 5, 6, 7, 10]) = fill( 7, [ 5, 6, 7, 10])
Note in particular the last one, fill(7, [5, 6, 7, 10]). One can spot its solution by inspection: only one filling of 7 is possible from sublengths [5, 6, 7, 10]. The recursion always ends with the solutions of these trivial cases. The ultimate solutions get assembled from these trivial ones.

Categories

Resources