Related
I have a problem using numpy fancy indexing which I somehow can't get my head around.
I know, that I can get an array of submatrices of rows like this:
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
B = A[np.array([[0,1],[1,2]])]
This gives:
array([[[1, 2, 3],
[4, 5, 6]],
[[4, 5, 6],
[7, 8, 9]]])
a threedimensional numpy array containing matrices comprising the first,second row and second,third row of A, respectively.
What I want is now basically the same operation for the cols of A which should give
array([[[1, 2],
[4, 5],
[7, 8]],
[[2, 3],
[5, 6],
[8, 9]]])
But
B = A[:,np.array([[0,1],[1,2]])]
does not work (probably because of the order of the index evaluations). It gives
array([[[1, 2],
[2, 3]],
[[4, 5],
[5, 6]],
[[7, 8],
[8, 9]]])
How can I accomplish this in the best way? Should I work with transposed matrices?
You get a (3,2,2) array:
In [417]: B
Out[417]:
array([[[1, 2],
[2, 3]],
[[4, 5],
[5, 6]],
[[7, 8],
[8, 9]]])
The 3 is from the first axis of A. The (2,2) from B.
Swap the first 2 axes:
In [418]: B.transpose(1,0,2)
Out[418]:
array([[[1, 2],
[4, 5],
[7, 8]],
[[2, 3],
[5, 6],
[8, 9]]])
A (2,3,2) array
try this:
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
B = A[np.array([[0,1,2],[0,1,2]])]
C = [list(), list()]
for i in range(2):
for j in range(3):
C[i].append(list(B[i][j][:2]) if i==0 else list(B[i][j][1:3]))
C = np.array(C)
C
output:
array([[[1, 2],
[4, 5],
[7, 8]],
[[2, 3],
[5, 6],
[8, 9]]])
One way could be to create B from A.T and then swapaxes:
import numpy as np
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
B = A.T[np.array([[0,1],[1,2]])]
C = B.swapaxes(-2,-1)
To check intermediate step and result:
B
array([[[1, 4, 7],
[2, 5, 8]],
[[2, 5, 8],
[3, 6, 9]]])
C
array([[[1, 2],
[4, 5],
[7, 8]],
[[2, 3],
[5, 6],
[8, 9]]])
Let's say I have a list of of list of 2 elements [[1 , 2], ...] in Python. Now I need to get something like this:
[2, 2] [2, 3] [3, 4] [3, 5] [3, 6] [3, 7]
Second element always goes up by 1, first element too, but occurs 2^n (n>=1) times, before going up.
So next will be 8 lists with first element 4, which occurs 8 times, second element of the lists will go up from 8 to 15.
Maybe you can try nested for loops like below
def fn(n, x):
for i in range(2, n+1):
for j in range(2**(i-1), 2**i):
x.append([i, j])
return(x)
or
from math import log2,ceil
def fn(n,x):
[x.append([ceil(log2(i)),i-1]) for i in range(3,2**n+1)]
return(x)
such that
>>> fn(3, [[1,2]])
[[1, 2], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6], [3, 7]]
>>> fn(4, [[1,2]])
[[1, 2], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6], [3, 7], [4, 8], [4, 9], [4, 10], [4, 11], [4, 12], [4, 13], [4, 14], [4, 15]]
from math import log
initial_list = [[1,2]]
def extend_pattern(initial_list,n):
last_sublist = initial_list[-1]
first_element = last_sublist[0]
for i in range(n):
last_sublist = list(last_sublist)
if i != 0:
last_sublist[1] += 1
last_sublist[0] = first_element + int(log(i+2,2))
initial_list.append(last_sublist)
extend_pattern(initial_list,10)
print(initial_list)
#[[1, 2], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6], [3, 7], [4, 8], [4, 9], [4, 10], [4, 11]]
Sounds like a fun homework.
If you intend a function with an output like this:
[[1, 1], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6], [3, 7], [4, 8], [4, 9], [4, 10]]
then this
def populate(n):
left=1
right=1
temp=right*2
output=[]
for i in range(0,n):
output.append([left,right])
right+=1
if(right==temp):
left+=1
temp=right*2
return output
is one of plenty ways to do it.
If you meant starting with a list and n something like this should work:
def populate(inputlist,n):
left=inputlist[len(inputlist)-1][0]+1
right=inputlist[len(inputlist)-1][1]+1
temp=right*2
for i in range(0,n):
inputlist.append([left,right])
right+=1
if(right==temp):
left+=1
temp=right*2
return inputlist
I want to sum a list of vectors in a list while keeping their dimension and list structure. How can this be done?
Given a vector
vecs = [[[1, 1], [2, 2], [3, 3], [4, 4]],[[5, 5], [6, 6], [7, 7],[8, 8]]]
and the expected output is
vecs_sum = [[10,10],[26,26]]
I tried the following, but it just returns [].
vec_sum = []
for inner_list in vec_sum:
temp = []
for arr in inner_list:
temp = [sum(x) for x in zip(arr)]
vec_sum.append(temp)
This is one approach using a list comprehension
Ex:
vecs = [[[1, 1], [2, 2], [3, 3], [4, 4]],[[5, 5], [6, 6], [7, 7],[8, 8]]]
vecs_sum = [list(map(sum, zip(*i))) for i in vecs]
print(vecs_sum)
Output:
[[10, 10], [26, 26]]
I have created a list where within it I seek to eliminate only the lists whose first value is greater than the second value of it.
I tried creating a second list with the elements to remove but I think it is not the most optimal way.
#y = []
x = [[1, 4], [1, 6], [2, 5], [2, 7], [4, 8], [6, 5], [6, 7], [2, 6], [3, 7], [5, 8], [6, 4], [7, 5]]
for i in range(len(x)):
if x[i][0] > x[i][1]:
print(x[i])
# y.append(x[i])
Is there an optimal way to achieve this?
I want that when printing on screen you get the following:
[[1, 4], [1, 6], [2, 5], [2, 7], [4, 8], [6, 7], [2, 6], [3, 7], [ 5, 8]]
Best regards,
This should work:
y = [[a,b] for a,b in x if a <= b]
Testing:
>>> x = [[1, 4], [1, 6], [2, 5], [2, 7], [4, 8], [6, 5], [6, 7], [2, 6], [3, 7], [5, 8], [6, 4], [7, 5]]
>>> y = [[a,b] for a,b in x if a < b]
>>> y
[[1, 4], [1, 6], [2, 5], [2, 7], [4, 8], [6, 7], [2, 6], [3, 7], [5, 8]]
>>>
This modifies the original list:
for i, (a, b) in enumerate(x):
if a > b:
del x[i]
Creating a new list:
[v for v in x if v[0] <= v[1]]
Or elimination in place:
for i in range(len(x) - 1, -1, -1): # need to start at the end
if x[i][0] > x[i][1]:
x.pop(i)
>>> filtered = list(filter(lambda f: f[0] < f[1], x))
>>> print(filtered)
This will create a new list with the desired values, using the built in filter(function, iterable) function.
I have the following list of lists (the inner lists will be referred to as tuples henceforth, just to avoid confusion) :
[[1, 1], [2, 1], [2, 2], [3, 1], [3, 2], [4, 1], [3, 3], [4, 2], [5, 1], [4, 3], [5, 2], [6, 1], [4, 4], [5, 3], [6, 2], [7, 1]]
and I would like to create another list that contains:
[[[1, 1]], [[2, 1], [2, 2]], [[3, 1], [3, 2]], [[4, 1], [3, 3], [4, 2]], [[5, 1], [4, 3], [5, 2]], [[6, 1], [4, 4], [5, 3], [6, 2]], [[7, 1]]]
What basically I am doing is scanning the list of tuples, and putting the tuples into sublists until I hit a tuple that has a higher first coordinate than the previous tuples (italics is a correction based on a comment, I had meant this but while writing, missed it). For example the first element is [1,1] and the next is [2,1], but since 2>1, the first sublist is [[1,1]]. Then again, when we hit [3,1], the second sublist created is [[2,1],[2,2]] and so on.
How do I implement this in python? Specifically python 3?
The following solution assumes that the input data is never an empty list:
d = [[1, 1], [2, 1], [2, 2], [3, 1], [3, 2], [4, 1], [3, 3], [4, 2], [5, 1], [4, 3], [5, 2], [6, 1], [4, 4], [5, 3], [6, 2], [7, 1]]
d2 = [[d[0]]]
for t in d[1:]:
if t[0] > d2[-1][0][0]:
d2.append([t])
else:
d2[-1].append(t)
print(d2)
The following accommodates the case where the input data is an empty list:
d2 = []
for t in d:
if (not d2) or (t[0] > d2[-1][0][0]):
d2.append([t])
else:
d2[-1].append(t)
a = [[1, 1], [2, 1], [2, 2], [3, 1], [3, 2], [4, 1], [3, 3], [4, 2], [5, 1], [4, 3], [5, 2], [6, 1], [4, 4], [5, 3], [6, 2], [7, 1]]
def cummax(v):
x = v[:1]
for i in v:
x.append(x[-1] if x[-1] > i else i)
return x
d = {}
for i,j in zip(cummax([i for i,j in a]), a):
if not d.get(i):
d[i]=[]
d[i].append(j)
list(d.values())
[[[1, 1]], [[2, 1], [2, 2]], [[3, 1], [3, 2]], [[4, 1], [3, 3], [4, 2]], [[5, 1], [4, 3], [5, 2]], [[6, 1], [4, 4], [5, 3], [6, 2]], [[7, 1]]]