Related
Let's say I got a dictionary defined this way: d ={(0, 1): 1, (1, 0): 4, (1, 3): 7, (2, 3): 11}
I want to convert it to a list in a way that each key represents that index of the value within the nested list and index of the nested list itself in the list. Each nested list has 4 items, indices with no defined values are set to 0.
I suck at describing. Here's what I want my function to return: lst = [[0,1,0,0], [4,0,0,7], [0,0,0,11]]. Here's my unfinished, non working code:
def convert):
lst = []
for i in range(len(d)):
lst += [[0,0,0,0]] # adding the zeros first.
for i in d:
for j in range(4):
lst[j] = list(i[j]) # and then the others.
How about:
for (x,y), value in d.items():
list[x][y] = value
Here is the entire function, which also creates the correct list size automatically
def convert(d):
# Figure out how big x and y can get
max_x = max([coord[0] for coord in d.keys()])
max_y = max([coord[1] for coord in d.keys()])
# Create a 2D array with the given dimensions
list = [[0] * (max_y + 1) for ix in range(max_x + 1)]
# Assign values
for (x,y), value in d.items():
list[x][y] = value
return list
if __name__ == "__main__":
d ={(0, 1): 1, (1, 0): 4, (1, 3): 7, (2, 3): 11}
print(convert(d))
# Input
example_d = {(0, 1): 1, (1, 0): 4, (1, 3): 7, (2, 3): 11}
def get_list(d):
# Figure out the required lengths by looking at the highest indices
max_list_idx = max(x for (x, _), _ in d.items())
max_sublist_idx = max(y for (_, y), _ in d.items())
# Create an empty list with the max sizes
t = [[0] * (max_sublist_idx + 1) for _ in range(max_list_idx + 1)]
# Fill out the empty list according to the input
for (x, y), value in d.items():
t[x][y] = value
return t
print(get_list(example_d))
# Output: [[0, 1, 0, 0], [4, 0, 0, 7], [0, 0, 0, 11]]
You can try this.
max_x=max(d,key=lambda x:x[0])[0] # For finding max number of rows
# 2
max_y=max(d,key=lambda x:x[1])[1] # For finding max of columns
# 3
new_list=[[0]*(max_y+1) for _ in range(max_x+1)] # Creating a list with max_x+1 rows and max_y+1 columns filled with zeros
# [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
for (x,y),v in d:
new_list[x][y]=v
new_list
# [[0, 1, 0, 0], [4, 0, 0, 7], [0, 0, 0, 11]]
You can use a list comprehension:
d ={(0, 1): 1, (1, 0): 4, (1, 3): 7, (2, 3): 11}
m_x, m_y = map(max, zip(*d))
m = [[d.get((b, a), 0) for a in range(m_y+1)] for b in range(m_x+1)]
Ouptut:
[[0, 1, 0, 0], [4, 0, 0, 7], [0, 0, 0, 11]]
I have a column vector y of length N containing a set of integers (1,2,3....K).
I want a matrix of size N x K of ones and zeros, as follows:
If the number in the vector y corresponds to the column index, the matrix has a one.
Otherwise, a zero.
Better with an example
y = [0,1,2,1]
Expected output
M = [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
[0, 1, 0]]
How can I implement this in python?
y = [0,1,2,1]
k = 3
arr = np.zeros((len(y),k))
for row, i in zip(arr, y):
row[i]=1
print(arr)
Without Using Numpy
y = [0,1,2,1]
k = 3
arr = [([0]*k).copy() for _ in range(len(y))]
for row, i in zip(arr, y):
row[i]=1
print(arr)
In [108]: M = np.zeros((4,3),int)
In [109]: M[np.arange(4), y] = 1
In [110]: M
Out[110]:
array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
[0, 1, 0]])
This assigns 1 to elements specified by (i, y(i)).
In [111]: list(zip(np.arange(4), y))
Out[111]: [(0, 0), (1, 1), (2, 2), (3, 1)]
My matrix is a 8x8 having binary values. I want to filter out patterns of consecutive three 1's i.e.(111) in the diagonals of upper triangular matrix of M. I have written a piece of python code with for and while loop but it did not work and I am unable to figure out whats happening there. Please help..
rf =([1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0],
[1,0,1,0,1,0,0,0])
for i in range(1):
for j in range(len (rf)-3):
while (i<len(rf)-3 and j<len(rf)-3):
count =0
if rf[i,j]==True:
for w in range(3):
if rf[i+w,j+w]==True:
count +=1
print count
if count==3:
i=i+3
j=j+3
else:
rf[i,j]=False
i=i+1
j=j+1
You might simplify your code using numpy to access diagonals:
>>> import numpy as np
>>> rf = [[1,0,1,0,1,0,0,0]] * 8
>>> m = np.array(rf)
>>> m.diagonal(0)
array([1, 0, 1, 0, 1, 0, 0, 0])
>>> m.diagonal(1)
array([0, 1, 0, 1, 0, 0, 0])
a simply routine to find positions of consecutive ones:
def consecutive_values(arr, val=1, cnt=3):
def comparator(pos):
return arr[pos] == val
if len < cnt:
return []
else:
return [p for p, x in enumerate(arr[:1-cnt])
if all(map(comparator, xrange(p, p+cnt, 1)))]
and usage:
>>> consecutive_values([1]*5)
[0, 1, 2]
>>> consecutive_values([1]*5 + [0]*4 + [1]*3)
[0, 1, 2, 9]
>>> m = np.array([[1]*8]*8)
>>> diagonals = map(m.diagonal, range(len(m)))
>>> map(consecutive_values, diagonals)
[[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4], [0, 1, 2, 3], [0, 1, 2], [0, 1], [0], [], []]
Problem:
Populate a 10 x 10 array of zeros randomly with 10 1's, 20 2's, 30 3's.
I don't actually have to use an array, rather I just need coordinates for the positions where the values would be. It's just easier to think of in terms of an array.
I have written several solutions for this, but they all seem to be non-straight forward and non-pythonic. I am hoping someone can give me some insight. My method has been using a linear array of 0--99, choosing randomly (np.random.choice) 10 values, removing them from the array, then choosing 20 random values. After that, I convert the linear positions into (y,x) coordinates.
import numpy as np
dim = 10
grid = np.arange(dim**2)
n1 = 10
n2 = 20
n3 = 30
def populate(grid, n, dim):
pos = np.random.choice(grid, size=n, replace=False)
yx = np.zeros((n,2))
for i in xrange(n):
delPos = np.where(grid==pos[i])
grid = np.delete(grid, delPos)
yx[i,:] = [np.floor(pos[i]/dim), pos[i]%dim]
return(yx, grid)
pos1, grid = populate(grid, n1, dim)
pos2, grid = populate(grid, n2, dim)
pos3, grid = populate(grid, n3, dim)
Extra
Suppose when I populate the 1's, I want them all on one half of the "array." I can do it using my method (sampling from grid[dim**2/2:]), but I haven't figured out how to do the same with the other suggestions.
You can create a list of all coordinates, shuffle that list and take the first 60 of those (10 + 20 + 30):
>>> import random
>>> coordinates = [(i, j) for i in xrange(10) for j in xrange(10)]
>>> random.shuffle(coordinates)
>>> coordinates[:60]
[(9, 5), (6, 9), (1, 5), ..., (0, 2), (5, 9), (2, 6)]
You can then use the first 10 to insert the 10 values, the next 20 for the 20 values and the remaining for the 30 values.
To generate the array, you can use numpy.random.choice.
np.random.choice([0, 1, 2, 3], size=(10,10), p=[.4, .1, .2, .3])
Then you can convert to coordinates. Note that numpy.random.choice generates a random sample using probabilities p, and thus you are not guaranteed to get the exact proportions in p.
Extra
If you want to have all the 1s on a particular side of the array, you can generate two random arrays and then hstack them. The trick is to slightly modify the probabilities of each number on each side.
In [1]: import numpy as np
In [2]: rem = .1/3 # amount to de- / increase the probability for non-1s
In [3]: A = np.random.choice([0, 1, 2, 3], size=(5, 10),
p=[.4-rem, .2, .2-rem, .3-rem])
In [4]: B = np.random.choice([0, 2, 3], size=(5, 10), p=[.4+rem, .2+rem, .3+rem])
In [5]: M = np.hstack( (A, B) )
In [6]: M
Out[1]:
array([[1, 1, 3, 0, 3, 0, 0, 1, 1, 0, 2, 2, 0, 2, 0, 2, 3, 3, 2, 0],
[0, 3, 3, 3, 3, 0, 1, 3, 1, 3, 0, 2, 3, 0, 0, 0, 3, 3, 2, 3],
[1, 0, 0, 0, 1, 0, 3, 1, 2, 2, 0, 3, 0, 3, 3, 0, 0, 3, 0, 0],
[3, 2, 3, 0, 3, 0, 1, 2, 3, 2, 0, 0, 0, 0, 3, 2, 0, 0, 0, 3],
[3, 3, 0, 3, 3, 3, 1, 3, 0, 3, 0, 2, 0, 2, 0, 0, 0, 3, 3, 3]])
Here, because I'm putting all the 1s on the left, I double the probability of 1 and decrease the probability of each number equally. The same logic applies when creating the other side.
Not sure if this is anymore "pythonic", but here's something I came up with using part of Simeon's answer.
import random
dim = 10
n1 = 10
n2 = 20
n3 = 30
coords = [[i,j] for i in xrange(dim) for j in xrange(dim)]
def setCoords(coords, n):
pos = []
for i in xrange(n):
random.shuffle(coords)
pos.append(coords.pop())
return(coords, pos)
coordsTmp, pos1 = setCoords(coords[dim**2/2:], n1)
coords = coords[:dim**2/2] + coordsTmp
coords, pos2 = setCoords(coords, n2)
coords, pos3 = setCoords(coords, n3)
I have something like this:
[e for e in ([n for n in xrange(random.randrange(1, 5))] for x in xrange(10))]
It produces:
[[0, 1, 2, 3], [0, 1, 2], [0], [0], [0, 1], [0], [0, 1], [0, 1, 2, 3], [0, 1, 2], [0, 1, 2]]
And I need the same but in flat structure.
For now I use something like:
l = []
[l.extend(e) for e in ([n for n in xrange(random.randrange(1, 5))] for x in xrange(10))]
But is there something less obsucre to achieve this 'unpacking' of arbitrary length list inside comprehension?
Use this list comprehension:
In [8]: [y for x in xrange(10) for y in xrange(random.randrange(1, 5))]
Out[8]: [0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 0, 1, 2, 3, 0, 0, 1, 0]
The above list comprehension is equivalent to this(but LC are much faster):
In [9]: lis=[]
In [10]: for x in xrange(10):
....: for y in xrange(random.randrange(1, 5)):
....: lis.append(y)
....:
The best way to flatten any iterable in a generic situation is itertools.chain.from_iterable():
>>> import random
>>> from itertools import chain
>>> x = [e for e in ([n for n in xrange(random.randrange(1, 5))]
... for x in xrange(10))]
>>> list(chain.from_iterable(x))
[0, 0, 0, 1, 2, 3, 0, 1, 2, 3, 0, 0, 1, 2, 3, 0, 1, 0, 1, 0, 0, 1, 2]
This said, it's preferable to avoid the extra work in this case by just making it flat to begin with.
You can use numpy flatten():
import numpy as np
l = [e for e in ([n for n in xrange(random.randrange(1, 5))] for x in xrange(10))]
a = np.asarray(l)
l = list(a.flatten(l))
print l
import itertools
l = [e for e in ([n for n in xrange(random.randrange(1, 5))] for x in xrange(10))]
result = list(itertools.chain(*l))
and then print result gives:
[0,1,2,3,0,1,2,0...]
the use of the * in chain(*l) is inspired from this question join list of lists in python .