Instead of the typical binary 0 or 1, or two consecutive numbers, I need to create a loop which will generate three random -1s and 1s, 100 times. My code so far looks like:
new = []
i =1
while i <= 100:
random = np.random.randint(low=-1, high=1, size=(1,3))
new.append(random)
i += 1
print(new.append(random))
Though this just returns None and even if it was working, would return 0s as well which is not wanted.
No need to bother importing numpy - it may be easier to just use random.choices() (from the standard library) to generate three random choices from [-1, 1], and do it 100 times.
import random
new = [random.choices([-1, 1], k=3) for _ in range(100)]
# [[1, 1, -1],
# [1, 1, 1],
# [1, 1, -1],
# [-1, -1, -1],
# ...
# [1, -1, 1]]
If you're doing this inside a function, with the intent for that function to produce new for outside use, then don't forget to do return new at the end of the function.
Related
I am trying to simulate a grid of spins in python that can change their orientation (represented by the sign):
>>> import numpy as np
>>> spin_values = np.random.choice([-1, 1], (2, 2))
>>> spin_values
array([[-1, 1],
[ 1, 1]])
I then throw two sets of random indices of that grid for spins that have a certain probability to switch their orientation, let's say:
>>> i = np.array([1, 1])
>>> j = np.array([0, 0])
>>> switches = np.array([-1, -1])
i and j here contain the indices that might change and switches states whether they do switch (-1) or keep their orientation (1). My idea for calculating the new orientations was:
>>> spin_values[i, j] *= switches
When a spin orientation only changes once this works fine. However, when it is supposed to change twice (as with the example values) it only changes once, therefore giving me a wrong result.
>>> spin_values
array([[-1, 1],
[-1, 1]])
How could I get the right results while having a short run time (this has to be done many times on a bigger grid)?
I would use numpy.unique to get the count of unique pairs of indices and compute -1 ** n:
idx, cnt = np.unique(np.vstack([i, j]), axis=1, return_counts=True)
spin_values[tuple(idx)] = (-1) ** cnt
Updated spin_values:
array([[-1, 1],
[ 1, 1]])
Hi I am new to python if I want to add row to an empty matrix after for loop in python how would I be able to do so. This is how I do it in Matlab.
n = 10000;
tic
A = [];
for i = 1:n
Ai = rand(1,3);
A = [A;Ai];
end
toc
You can use append to add rows at the end of an array:
a = []
for i in range(10):
a.append([1,2,3])
print a
For example:
Add a list to an empty matrix as a row where [i for i in range(4)] will give you a list [0,1,2,3]
#empty matrix
mat = []
mat.append([i for i in range(4)])
print mat
#output
[[0,1,2,3]]
A one-liner:
import random
matrix = [[random.randint(1, 3) for _ in range(10)]]
I wonder why would you need a one-row "matrix", as opposed to just a list of random numbers.
If you want a matrix with 1000 identical rows, create a row and add it 1000 times.
row = [random.randint(1, 3) for _ in range(10)]
matrix = [row for _ in range(1000)]
Or a funny syntax-sugared version:
matrix = [row] * 1000
Please note that the matrix will have 1000 references to the same row, not 1000 different copies of the row. If you mutate any value in any row, it will affect every row.
If you want a mutable matrix initially filled with 1000 identical rows, make a copy of the row each time:
matrix = [list(row) for _ in range(1000)]
Each invocation of list creates a new list filled with numbers from row.
Try to use numpy.random
import numpy as np
A = np.random.randint(1,4, size=(1000, 3))
and A should be the matrix you want.
For example,
import numpy as np
a = np.random.randint(1,4, size=(10, 3))
a looks like:
array([[1, 3, 3],
[3, 1, 1],
[2, 2, 1],
[3, 2, 3],
[2, 1, 2],
[3, 3, 2],
[2, 1, 2],
[1, 1, 2],
[2, 1, 1],
[1, 1, 3]])
import numpy as np
a = []
for i in range(2):
ai = np.random.rand(1,3)
a.append([ai])
print a
I'm working on a project involving binary patterns (here np.arrays of 0 and 1).
I'd like to modify a random subset of these and return several altered versions of the pattern where a given fraction of the values have been changed (like map a function to a random subset of an array of fixed size)
ex : take the pattern [0 0 1 0 1] and rate 0.2, return [[0 1 1 0 1] [1 0 1 0 1]]
It seems possible by using auxiliary arrays and iterating with a condition, but is there a "clean" way to do that ?
Thanks in advance !
The map function works on boolean arrays too. You could add the subsample logic to your function, like so:
import numpy as np
rate = 0.2
f = lambda x: np.random.choice((True, x),1,p=[rate,1-rate])[0]
a = np.array([0,0,1,0,1], dtype='bool')
map(f, a)
# This will output array a with on average 20% of the elements changed to "1"
# it can be slightly more or less than 20%, by chance.
Or you could rewrite a map function, like so:
import numpy as np
def map_bitarray(f, b, rate):
'''
maps function f on a random subset of b
:param f: the function, should take a binary array of size <= len(b)
:param b: the binary array
:param rate: the fraction of elements that will be replaced
:return: the modified binary array
'''
c = np.copy(b)
num_elem = len(c)
idx = np.random.choice(range(num_elem), num_elem*rate, replace=False)
c[idx] = f(c[idx])
return c
f = lambda x: True
b = np.array([0,0,1,0,1], dtype='bool')
map_bitarray(f, b, 0.2)
# This will output array b with exactly 20% of the elements changed to "1"
rate=0.2
repeats=5
seed=[0,0,1,0,1]
realizations=np.tile(seed,[repeats,1]) ^ np.random.binomial(1,rate,[repeats,len(seed)])
Use np.tile() to generate a matrix from the seed row.
np.random.binomial() to generate a binomial mask matrix with your requested rate.
Apply the mask with the xor binary operator ^
EDIT:
Based on #Jared Goguen comments, if you want to change 20% of the bits, you can elaborate a mask by choosing elements to change randomly:
seed=[1,0,1,0,1]
rate=0.2
repeats=10
mask_list=[]
for _ in xrange(repeats):
y=np.zeros(len(seed),np.int32)
y[np.random.choice(len(seed),0.2*len(seed))]=1
mask_list.append(y)
mask = np.vstack(mask_list)
realizations=np.tile(seed,[repeats,1]) ^ mask
So, there's already an answer that provides sequences where each element has a random transition probability. However, it seems like you might want an exact fraction of the elements to change instead. For example, [1, 0, 0, 1, 0] can change to [1, 1, 0, 1, 0] or [0, 0, 0, 1, 0], but not [1, 1, 1, 1, 0].
The premise, based off of xvan's answer, uses the bit-wise xor operator ^. When a bit is xor'd with 0, it's value will not change. When a bit is xor'd with 1, it will flip. From your question, it seems like you want to change len(seq)*rate number of bits in the sequence. First create mask which contains len(seq)*rate number of 1's. To get an altered sequence, xor the original sequence with a shuffled version of mask.
Here's a simple, inefficient implementation:
import numpy as np
def edit_sequence(seq, rate, count):
length = len(seq)
change = int(length * rate)
mask = [0]*(length - change) + [1]*change
return [seq ^ np.random.permutation(mask) for _ in range(count)]
rate = 0.2
seq = np.array([0, 0, 1, 0, 1])
print edit_sequence(seq, rate, 5)
# [0, 0, 1, 0, 0]
# [0, 1, 1, 0, 1]
# [1, 0, 1, 0, 1]
# [0, 1, 1, 0, 1]
# [0, 0, 0, 0, 1]
I don't really know much about NumPy, so maybe someone with more experience can make this efficient, but the approach seems solid.
Edit: Here's a version that times about 30% faster:
def edit_sequence(seq, rate, count):
mask = np.zeros(len(seq), dtype=int)
mask[:len(seq)*rate] = 1
output = []
for _ in range(count):
np.random.shuffle(mask)
output.append(seq ^ mask)
return output
It appears that this updated version scales very well with the size of seq and the value of count. Using dtype=bool in seq and mask yields another 50% improvement in the timing.
I have some complex assignment logic in a simulation that I would like to optimize for performance. The current logic is implemented as a set of nested for loops over a variety of numpy arrays. I would like to vectorize this assignment logic but haven't been able to figure out if this is possible
import numpy as np
from itertools import izip
def reverse_enumerate(l):
return izip(xrange(len(l)-1, -1, -1), reversed(l))
materials = np.array([[1, 0, 1, 1],
[1, 1, 0, 0],
[0, 1, 1, 1],
[1, 0, 0, 1]])
vectors = np.array([[1, 1, 0, 0],
[0, 0, 1, 1]])
prices = np.array([10, 20, 30, 40])
demands = np.array([1, 1, 1, 1])
supply_by_vector = np.zeros(len(vectors)).astype(int)
#go through each material and assign it to the first vector that the material covers
for m_indx, material in enumerate(materials):
#find the first vector where the material covers the SKU
for v_indx, vector in enumerate(vectors):
if (vector <= material).all():
supply_by_vector[v_indx] = supply_by_vector[v_indx] + 1
break
original_supply_by_vector = np.copy(supply_by_vector)
profit_by_vector = np.zeros(len(vectors))
remaining_ask_by_sku = np.copy(demands)
#calculate profit by assigning material from vectors to SKUs to satisfy demand
#go through vectors in reverse order (so lowest priority vectors are used up first)
profit = 0.0
for v_indx, vector in reverse_enumerate(vectors):
for sku_indx, price in enumerate(prices):
available = supply_by_vector[v_indx]
if available == 0:
continue
ask = remaining_ask_by_sku[sku_indx]
if ask <= 0:
continue
if vector[sku_indx]:
assign = ask if available > ask else available
remaining_ask_by_sku[sku_indx] = remaining_ask_by_sku[sku_indx] - assign
supply_by_vector[v_indx] = supply_by_vector[v_indx] - assign
profit_by_vector[v_indx] = profit_by_vector[v_indx] + assign*price
profit = profit + assign * price
print 'total profit:', profit
print 'unfulfilled demand:', remaining_ask_by_sku
print 'original supply:', original_supply_by_vector
result:
total profit: 80.0
unfulfilled demand: [0 1 0 0]
original supply: [1 2]
It seems there is a dependency between iterations within the innermost nested loop in the second part/group of the nested loops and that to me seemed like difficult if not impossible to vectorize. So, this post is basically a partial solution trying to vectorize instead the first group of two nested loops, which were -
supply_by_vector = np.zeros(len(vectors)).astype(int)
for m_indx, material in enumerate(materials):
#find the first vector where the material covers the SKU
for v_indx, vector in enumerate(vectors):
if (vector <= material).all():
supply_by_vector[v_indx] = supply_by_vector[v_indx] + 1
break
That entire section could be replaced by one line of vectorized code, like so -
supply_by_vector = ((vectors[:,None] <= materials).all(2)).sum(1)
How to make the loop faster?
import numpy as np
# naively small input data
image = np.array( [[2,2],[2,2]] )
polarImage = np.array( [[0,0],[0,0]] )
a = np.array( [[0,0],[0,1]] )
r = np.array( [[0,0],[0,1]] )
# TODO - this loop is too slow
it = np.nditer(image, flags=['multi_index'])
while not it.finished:
polarImage[ a[it.multi_index],r[it.multi_index] ] += it[0]
it.iternext()
print polarImage
# this is fast but doesn't cumulate the results!
polarImage = np.array( [[0,0],[0,0]] )
polarImage[a,r]+= image
print polarImage
The first print returns:
[[6 0]
[0 2]]
The second:
[[2 0]
[0 2]]
By the cumulative addition I mean that sometimes two or more values from image has to be added together to one cell of polarImage
In this case the use of nditer obscures the process, without improving the speed. We are more used to seeing a double loop:
In [670]: polarImage=np.zeros_like(image)
In [671]: for i in range(2):
for j in range(2):
polarImage[a[i,j],r[i,j]] += image[i,j]
In [672]: polarImage
Out[672]:
array([[6, 0],
[0, 2]])
polarImage[a,r]+= image doesn't work because of buffering issues. The (0,0) index pair is used 3 times. There is a ufunc method specifically for this case, at. It performs unbuffered operations; quite possibly using the same nditer of your first example, but in compiled code.
In [676]: polarImage=np.zeros_like(image)
In [677]: np.add.at(polarImage, (a,r), image)
In [678]: polarImage
Out[678]:
array([[6, 0],
[0, 2]])