filling numpy array with random element from another array - python

I'm not sure if this is possible but here goes. Suppose I have an array:
array1 = [0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1]
and now I would like to create a numpy 1D array consisting of 5 elements that are randomly drawn from array1 AND with the condition that the sum is equal to 1. Example is something like, a numpy array that looks like [.2,.2,.2,.1,.1].
currently I use the random module, and choice function that looks like this:
range1= np.array([choice(array1),choice(array1),choice(array1),choice(array1),choice(array1)])
then checking range1 to see if it meets the criteria; I'm wondering if there is faster way , something similar to
randomArray = np.random.random() instead.
Would be even better if I can store this array in some library so that if I try to generate 100 of such array, that there is no repeat but this is not necessary.

You can use numpy.random.choice if you use numpy 1.7.0+:
>>> import numpy as np
>>> array1 = np.array([0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1])
>>> np.random.choice(array1, 5)
array([ 0. , 0. , 0.3, 1. , 0.3])
>>> np.random.choice(array1, 5, replace=False)
array([ 0.6, 0.8, 0.1, 0. , 0.4])
To get 5 elements that the sum is equal to 1,
generate 4 random numbers.
substract the sum of 4 numbers from 1 -> x
if x included in array1, use that as final number; or repeat
>>> import numpy as np
>>>
>>> def solve(arr, total, n):
... while True:
... xs = np.random.choice(arr, n-1)
... remain = total - xs.sum()
... if remain in arr:
... return np.append(xs, remain)
...
>>> array1 = np.array([0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1])
>>> print solve(array1, 1, 5)
[ 0.1 0.3 0.4 0.2 0. ]
Another version (assume given array is sorted):
EPS = 0.0000001
def solve(arr, total, n):
while True:
xs = np.random.choice(arr, n-1)
t = xs.sum()
i = arr.searchsorted(total - t)
if abs(t + arr[i] - total) < EPS:
return np.append(xs, arr[i])

I had to do something similar a while ago.
def getRandomList(n, source):
'''
Returns a list of n elements randomly selected from source.
Selection is done without replacement.
'''
list = source
indices = range(len(source))
randIndices = []
for i in range(n):
randIndex = indices.pop(np.random.randint(0, high=len(indices)))
randIndices += [randIndex]
return [source[index] for index in randIndices]
data = [1,2,3,4,5,6,7,8,9]
randomData = getRandomList(4, data)
print randomData

If you don't care about the order of the values in the output sequences, the number of 5-value combinations of values from your list that add up to 1 is pretty small. In the specific case you proposed though, it's a bit complicated to calculate, since floating point values have rounding issues. You can more easily solve the issue if you use a set of integers (e.g. range(11))and find combinations that add up to 10. Then if you need the fractional values, just divide the values in the results by 10.
Anyway, here's a generator that yields all the possible sets that add up to a given value:
def picks(values, n, target):
if n == 1:
if target in values:
yield (target,)
return
for i, v in enumerate(values):
if v <= target:
for r in picks(values[i:], n-1, target-v):
yield (v,)+r
Here's the results for the numbers zero through ten:
>>> for r in picks(range(11), 5, 10):
print(r)
(0, 0, 0, 0, 10)
(0, 0, 0, 1, 9)
(0, 0, 0, 2, 8)
(0, 0, 0, 3, 7)
(0, 0, 0, 4, 6)
(0, 0, 0, 5, 5)
(0, 0, 1, 1, 8)
(0, 0, 1, 2, 7)
(0, 0, 1, 3, 6)
(0, 0, 1, 4, 5)
(0, 0, 2, 2, 6)
(0, 0, 2, 3, 5)
(0, 0, 2, 4, 4)
(0, 0, 3, 3, 4)
(0, 1, 1, 1, 7)
(0, 1, 1, 2, 6)
(0, 1, 1, 3, 5)
(0, 1, 1, 4, 4)
(0, 1, 2, 2, 5)
(0, 1, 2, 3, 4)
(0, 1, 3, 3, 3)
(0, 2, 2, 2, 4)
(0, 2, 2, 3, 3)
(1, 1, 1, 1, 6)
(1, 1, 1, 2, 5)
(1, 1, 1, 3, 4)
(1, 1, 2, 2, 4)
(1, 1, 2, 3, 3)
(1, 2, 2, 2, 3)
(2, 2, 2, 2, 2)
You can select one of them at random (with random.choice), or if you plan on using many of them and you don't want to repeat yourself, you can use random.shuffle, then iterate.
results = list(picks(range(11), 5, 10))
random.shuffle(results)
for r in results:
# do whatever you want with r

Related

Numpy: How to check if a number is the minimum/maximum among the previous K numbers?

I'm trying to automate a trading strategy which should enter/exit a long position when the current price is the minimum/maximum among the previous k prices.
The result should contain 1 if the current number is maximum among previous k numbers, -1 if it is the minimum and 0 if none of the conditions are true.
For example if k = 3 and the numpyp array = [1, 2, 3, 2, 1, 6], the result should be an array like:
[0, 0, 1, 0, -1, 1].
I tried the numpy's max function but don't know how to take into account the previous k numbers instead of fixed index and how to switch to default condition for the first k - 1 numbers which should be 0 since there are not k number available to compare them with.
I will use Pandas
import pandas as pd
array = [1, 2, 3, 2, 1, 6]
df = pd.DataFrame(array)
df['rolling_max'] = df[0].rolling(3).max()
df['rolling_min'] = df[0].rolling(3).min()
df['result'] = df.apply(lambda row: 1 if row[0] == row['rolling_max'] else (-1 if row[0] == row['rolling_min'] else 0), axis=1)
Here is a solution with numpy using numpy.lib.stride_tricks.sliding_window_view, which was introduced in version 1.20.0.
Note that this solution (like the one proposed by #Hanwei Tang) does not exactly yield the result you was looking for, because in the second window ([2, 3, 2]) 2 is the minimum value and thus a -1 is returned instead of zero (what you requested). But maybe you should rethink whether you really want a zero for the second window or a -1.
EDIT: If a windows only contains same numbers, i.e. the minimum and maximum are the same, this method returns a zero.
import numpy as np
def rolling_max(a, wsize):
windows = np.lib.stride_tricks.sliding_window_view(a, wsize)
return np.max(windows, axis=-1)
def rolling_min(a, wsize):
windows = np.lib.stride_tricks.sliding_window_view(a, wsize)
return np.min(windows, axis=-1)
def check_prize(a, wsize):
rmax = rolling_max(a, wsize)
rmin = rolling_min(a, wsize)
ismax = np.where(a[wsize-1:] == rmax, 1, 0)
ismin = np.where(a[wsize-1:] == rmin, -1, 0)
result = np.zeros_like(a)
result[wsize-1:] = ismax + ismin
return result
a = np.array([1, 2, 3, 2, 1, 6])
check_prize(a, wsize=3)
# Output:
# array([ 0, 0, 1, -1, -1, 1])
b = np.array([1, 2, 4, 3, 1, 6])
check_prize(b, wsize=3)
# Output:
# array([ 0, 0, 1, 0, -1, 1])
c = np.array([1, 2, 2, 2, 1, 6])
check_prize(c, wsize=3)
# Output:
# array([ 0, 0, 1, 0, -1, 1])
Another approach using sliding_window_view with pad:
from numpy.lib.stride_tricks import sliding_window_view as swv
k = 3
a = np.array([1, 2, 3, 2, 1, 6])
# create sliding window
v = swv(np.pad(a.astype(float), (k-1, 0), constant_values=np.nan), k)
# compare each element to min/max of sliding window
out = np.select([np.max(v, 1)==a, np.min(v, 1)==a], [1, -1], 0)
Output: array([ 0, 0, 1, -1, -1, 1])

How to find the highest value according to specified certain conditions in for loop?

I managed to put the arrays in for loop and, depending on the condition, select the values I need. From these selected values I try to choose the highest value from the matrix a and b. Unfortunately, somehow I miss some syntax.
my code
a=np.array([0, 0, 0, 1, 1, 1, 2, 4,2, 2])
b=np.array([0, 1, 2, 0, 1, 2, 0, 1, 2,5])
max_b=b[0]
for (j), (k) in zip(a,b):
#print(j,k)
if j>=2 and k>=1:
print(j,'a')
print(k,'b')
output:
4 a
1 b
2 a
2 b
2 a
5 b
i need : From these numbers I need to choose the largest number from j and k
4 a
5 b
I also created the code specifically to get the highest value in the loop from one matrix without other conditions to make it work better, but I can't incorporate it correctly into my code
maxv=a[0]
for i in a:
if i > maxv:
maxv=i
print(maxv)
This is my attempt, but it is stupid
a=np.array([0, 0, 0, 1, 1, 1, 2, 4,2, 2])
b=np.array([0, 1, 2, 0, 1, 2, 0, 1, 2,5])
#max_b=b[0]
for (j), (k) in zip(a,b):
#print(j,k)
if j>=2 and k>=1:
#print(j,'a')
# print(k,'b')
max_a=j
max_b=k
if j > max_a:
max_a=k
print(max_a)
Can you advise me how it could work?
A correct solution using for loops follows.
You were not updating max_b, not keeping max_a at all, and not checking if the current max_b or max_a is smaller than the current value in order to update them.
import numpy as np
a = np.array([0, 0, 0, 1, 1, 1, 2, 4, 2, 2])
b = np.array([0, 1, 2, 0, 1, 2, 0, 1, 2, 5])
max_a = a[0]
max_b = b[0]
for j, k in zip(a, b):
# print(j,k)
if j >= 2 and k >= 1:
if max_a < j :
max_a = j
if max_b < k:
max_b = k
print(f"{max_a}, a)")
print(f"{max_b}, b)")
We can use numpy's masking, then .max().
This is a no-for-loops solution, also called vectorization.
import numpy as np
a = np.array([0, 0, 0, 1, 1, 1, 2, 4, 2, 2])
b = np.array([0, 1, 2, 0, 1, 2, 0, 1, 2, 5])
a_gt_2 = a >= 2
b_gt_1 = b >= 1
conditions_apply_mask = a_gt_2 & b_gt_1
a_filtered = a[conditions_apply_mask]
b_filtered = b[conditions_apply_mask]
max_a_filtered = a_filtered.max()
max_b_filtered = b_filtered.max()
print(f"{max_a_filtered}, a")
print(f"{max_b_filtered}, b")

Generate image matrix from Freeman chain code

Suppose I have a 8-direction freeman chain code as follows, in a python list:
freeman_code = [3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5]
Where directions would be defined as follows:
I need to convert this to an image matrix of variable dimensions with valules of 1s and 0s where 1s would depict the shape, as follows, for example:
image_matrix = [
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 1, 1]
]
Of course, the above is not an exact implementation of the above freeman code. Is there any implementation in python, or in any language that achieves this?
My idea (in python):
Use a defaultdict of defaultdicts with 0 as default:
ImgMatrixDict = defaultdict(lambda: defaultdict(lambda:0))
and then start at a midpoint, say ImgMatrixDict[25][25], and then change values to 1 depending on the freeman code values as I traverse. Afte tis I would convert ImgMatrixDict to a list of lists.
Is this a viable idea or are there any existing libraries or suggestions to implement this? Any idea/pseudo-code would be appreciated.
PS: On performance, yes it would not be important as I won't be doing this in realtime, but generally a code would be around 15-20 charactors in length. I assumed a 50*50 by matrix would suffice for this purpose.
If I am understanding your question correctly:
import numpy as np
import matplotlib.pyplot as plt
freeman_code = [3, 3, 3, 6, 6, 4, 6, 7, 7, 0, 0, 6]
img = np.zeros((10,10))
x, y = 4, 4
img[y][x] = 1
for direction in freeman_code:
if direction in [1,2,3]:
y -= 1
if direction in [5,6,7]:
y += 1
if direction in [3,4,5]:
x -= 1
if direction in [0,1,7]:
x += 1
img[y][x] = 1
plt.imshow(img, cmap='binary', vmin=0, vmax=1)
plt.show()
Here is a solution in python. A dictionary is not adapted to this problem, you would better use a list of list to simulate the table.
D = 10
# DY, DX
FREEMAN = [(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)]
freeman_code = [3, 3, 3, 3, 6, 6, 6, 6, 0, 0, 0, 0]
image = [[0]*D for x in range(D)]
y = D/2
x = D/2
image[y][x] = 1
for i in freeman_code:
dy, dx = FREEMAN[i]
y += dy
x += dx
image[y][x] = 1
print("freeman_code")
print(freeman_code)
print("image")
for line in image:
strline = "".join([str(x) for x in line])
print(strline)
>0000000000
>0100000000
>0110000000
>0101000000
>0100100000
>0111110000
>0000000000
>0000000000
>0000000000
>0000000000
Note that the image creation is a condensed expression of:
image = []
for y in range(D):
line = []
for x in range(D):
line.append(0)
image.append(line)
If one day, you need better performance for bigger images, there are solutions using numpy Library but requiring a good knowledge of basic python. Here is an example:
import numpy as np
D = 10
# DY, DX
FREEMAN = [(0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (1, 1)]
DX = np.array([1, 1, 0, -1, -1, -1, 0, 1])
DY = np.array([0, -1, -1, -1, 0, 1, 1, 1])
freeman_code = np.array([3, 3, 3, 3, 6, 6, 6, 6, 0, 0, 0, 0])
image = np.zeros((D, D), int)
y0 = D/2
x0 = D/2
image[y0, x0] = 1
dx = DX[freeman_code]
dy = DY[freeman_code]
xs = np.cumsum(dx)+x0
ys = np.cumsum(dy)+y0
print(xs)
print(ys)
image[ys, xs] = 1
print("freeman_code")
print(freeman_code)
print("image")
print(image)
Here, all loops built with 'for' on previous solution are fast-processed in C.

Changing One Element in 2-Dimensional List Changes all Duplicates of List in List

The purpose of my code is to create a list of lists that contains all combinations of two switches on a binary list.
For example a two switch of [1,0,0,1,0] would be [0,0,0,1,1]
I have code written that makes the first switch. I'm trying to write code that takes input of the first switches and makes a second switch. The order of the input is based on where the first switch was made. So, the first element-list had it's first switch in its first element, the second element-list had its switch in the second element etc... I will not switch those elements since it would be undoing the first switch.
Below is what I have. The nbrhood list is the hypothetical list of lists that have already had one switch
import itertools
n = 4
nbrhood = [[1,1,1,1],[0,0,0,0]]
nbrhood2 = list(itertools.chain.from_iterable(itertools.repeat(x, (n-1)) for x in nbrhood))
print(nbrhood2)
h = 0
f = 0
for j in range(0,6):
f = j//(n-1)
if n <= h:
h = 0
if h != f and h <= n:
if nbrhood2[j][h] == 1:
nbrhood2[j][h] = 0
else:
nbrhood2[j][h] = 1
h = h + 1
elif h == f and h <= n:
if nbrhood2[j][h+1] == 1:
nbrhood2[j][h+1] = 0
else:
nbrhood2[j][h+1] = 1
h = h + 2
elif h >= n:
h = 0
print(nbrhood2[j])
This is the unexpected output:
[1, 0, 1, 1]
[1, 0, 0, 1]
[1, 0, 0, 0]
[1, 0, 0, 0]
[1, 0, 1, 0]
[1, 0, 1, 1]
I need the output to look like this:
[1, 0, 1, 1]
[1, 1, 0, 1]
[1, 1, 1, 0]
[1, 0, 0, 0]
[0, 0, 1, 0]
[0, 0, 0, 1]
I don't understand the change I make to one list in nbrhood2 also applies to the other lists. Like how the 0 put in the second position in the first list also goes to the second position in the second list.
I've been working on this for hours with no real explanation. I imagine it has something to do with how Python treats two-dimensional list changes, but I haven't been able to figure it out.
Lists in Python are always by-reference. You're literally repeating the nested values of in nbrhood when you do itertools.repeat(x, (n-1)) for x in nbrhood.
Simply copy the full list by replacing the first x with x[:]:
itertools.repeat(x[:], (n-1)) for x in nbrhood
It is quite simple to create a list with all combinations
l = list(itertools.product([0,1], repeat=4))
[[i] for i in l]
Output
[[(0, 0, 0, 0)], [(0, 0, 0, 1)], [(0, 0, 1, 0)], [(0, 0, 1, 1)], [(0, 1, 0, 0)], [(0, 1, 0, 1)], [(0, 1, 1, 0)], [(0, 1, 1, 1)], [(1, 0, 0, 0)], [(1, 0, 0, 1)], [(1, 0, 1, 0)], [(1, 0, 1, 1)], [(1, 1, 0, 0)], [(1, 1, 0, 1)], [(1, 1, 1, 0)], [(1, 1, 1, 1)]]
You could iterate across all items for the first switch and in a nested loop iterate across all subsequent items for the second switch. Having the inner loop start at the item after the index of the outer loop ensures that you don't duplicate your coverage.
def two_switch(original):
list_of_2_switches = []
for i in range(len(original)):
one_switch = original[:] #copy to retain original
one_switch[i]=1-one_switch[i]
for j in range(i+1, range(len(original))):
second_switch=one_switch[:]
second_switch[j] = 1-second_switch[j]
lit_of_2_switches.append(second_switch)
return list_of_2_switches

Modify only a specific tuple in python (incomprehensible)

I have a list of 10,000 tuples.
Each tuple has 31 entries.
Let's say I just want to modify only the first entry of the 77th tuple.
empty_tuple=[0] * 31
lst=[empty_tuple] * 10000
lst[77][0]='salut'
It does work but all the first entries of all the 10,000 tuples are now the same.
What's going on here?
print lst[1987][0]
'salut'
[empty_tuple] * 10000 creates a list that contains 10000 references to empty_tuple, so when you modify it with lst[77][0]=..., it will be reflected across all of l.
It's a bit tricky if you really want to use tuples, as they are immutable, but you can do something like:
>>> sett = lambda t, idx, val: tuple((v if i != idx else val) for i,v in enumerate(t))
>>> l = [(0,) * 3] * 4
>>> l
[(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]
>>> l[1] = sett(l[1], 2, 42)
>>> l
[(0, 0, 0), (0, 0, 42), (0, 0, 0), (0, 0, 0)]
where sett is a function that takes a tuple t, an index idx, and a value val, and returns a tuple that is identical to t in every index but idx, where it contains val.
One way to set up a list of distinct lists would be:
>>> l = map(lambda _: [0] * 3, xrange(4))
>>> l[0][1] = 2
>>> l
[[0, 2, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

Categories