unable to copy random generated values in to variable using tensorflow - python

I have data in one array say size [1x9] , I am generating random number 1 to 9 and shuffling it, I want to arrange data in that order.
# generating an array of number
BCI = tf.concat(0, [tf.fill([1,3],1),tf.fill([1,3],2),tf.fill([1,3],3)])
# making it in to 1x9
BCI1 = tf.reshape(BCI,[-1])
# generating random numbers with length of BCI and shuffling it
rn = tf.random_shuffle(tf.range(tf.shape(BCI1[0]))
rna = tf.cast(rn,tf.int32)
# rearranging data
BCI2 = tf.gather(BCI1,rna)
print(sess.run(BCI1))
print(sess.run(rn))
print(sess.run(BCI2))
# output is
[1 1 1 2 2 2 3 3 3]
[3 5 0 2 6 1 4 8 7]
[2 2 1 3 1 2 1 3 3] # expected to be [2 2 1 1 3 1 2 3 3]
It because I am not able to copy rn value as constant , when I am running sess.run every time it is changing.
But I need the random values generated in 'rn' first time generated as i need for testing on another ones.
How many times i print rn it should show the same values with out regenerating again.
How to do it ?
I tried by importing random
n = tf.shape(BCI1)
rna = random.sample(list(range(n[0].eval())),9)
but it gives ValueError: Cannot evaluate tensor using eval(): No default session is registered. Use with sess.as_default() or pass an explicit session to eval(session=sess)
`

The tf.random_shuffle() op (and in general the other tf.random_*() ops) will generate new random values on each call to sess.run(). If you want to capture a particular value for a random tensor and use it in multiple calls to sess.run(), you should assign it to a tf.Variable. For example, you could restructure your program as follows to solve the problem:
# generating an array of number
BCI = tf.constant([1, 1, 1, 2, 2, 2, 3, 3, 3])
# generating random numbers with length of BCI and shuffling it
rn = tf.Variable(tf.random_shuffle(tf.range(9)))
rna = tf.cast(rn,tf.int32)
# rearranging data
BCI2 = tf.gather(BCI1, rna)
sess.run(tf.global_variables_initializer())
print(sess.run(BCI1)) # ==> '[1 1 1 2 2 2 3 3 3]'
print(sess.run(rn)) # ==> '[2 8 3 0 1 4 6 5 7]'
print(sess.run(BCI2)) # ==> '[1 3 2 1 1 2 3 2 3]'
print(sess.run(BCI2)) # ==> '[1 3 2 1 1 2 3 2 3]'

Related

Vectorised np.random.choice with varying probabilities

I've trained a machine learning model using sklearn and want to simulate the result by sampling the predictions according to the predict_proba probabilities. So I want to do something like
samples = np.random.choice(a = possible_outcomes, size = (n_data, n_samples), p = probabilities)
Where probabilities would be is an (n_data, n_possible_outcomes) array
But np.random.choice only allows 1d arrays for the p argument. I've currently gotten around this using a for-loop like the following implementation
sample_outcomes = np.zeros((len(probs), n_samples))
for i in trange(len(probs)):
sample_outcomes[i, :] = np.random.choice(outcomes, s = n_samples, p=probs[i])
but that's relatively slow. Any suggestions to speed this up would be much appreciated!
If I understood correctly you want a vectorize way of applying choice
several times and each time with a different probabilities vector.
You could implement this by hand as follows:
import numpy as np
# for reproducibility
np.random.seed(42)
# number of samples
k = 5
# possible outcomes
outcomes = np.arange(10)
# generate a random probability matrix for 15 runs
probabilities = np.random.random((15, 10))
probs = probabilities / probabilities.sum(1)[:, None]
# generate the choices by picking those probabilities above a random generated number
# the higher the value in probs the higher the probability to pick it
choices = probs - np.random.random((15, 10))
# to pick the top k using argpartition need to multiply by -1
choices = -1 * choices
# pick the top k values
res = outcomes[np.argpartition(choices, k, axis=1)][:, :k]
# flatten to match the expected output
print(res.flatten())
Output
[1 8 2 5 3 6 4 8 7 0 1 5 9 3 7 1 4 9 0 8 5 0 4 3 6 8 5 1 2 6 5 3 2 0 6 5 4
2 3 7 7 9 4 6 1 3 6 4 2 1 4 9 3 0 1 6 9 2 3 8 5 4 7 6 1 5 3 8 2 1 1 0 9 7
4]
In the above example the code sample 5 (k) elements from a population of 10 (outcomes) 15 times each time with a different probability vector (probs with a shape of 15 by 10).
Here is an example of what you can do, if I understand your question correctly:
import numpy as np
#create a list of indices
index_list = np.arange(len(possible_outcomes))
# sample indices based on the probabilities
choice = np.random.choice(a = index_list, size = n_samples, p = probabilities)
# get samples based on randomly chosen indices
samples = possible_outcomes[choice]
I'm making sure I understand you problem correctly. Can you just create samples as an array of size n_data * n_samples and then use the resize method to get it to the right size?
samples = np.random.choice(a = possible_outcomes, size = n_data * n_samples, p = probabilities)
samples.resize((n_data, n_samples))

Print the minimum number of moves required such that all the elements are equal to minimum element

In one move we can make it equal to the 2nd maximum element and have to make all elements equal to the minimum element.
My code is given below it works fine but I want to reduce its time complexity.
def No_Books(arr, n):
arr = sorted(arr)
steps = 0
while arr[0]!= arr[arr.index(max(arr))]:
max1 = max(arr)
count = arr.count(max1)
scnd_max = arr.index(max1)-1
arr[scnd_max+count] = arr[scnd_max]
steps += 1
return steps
n = int(input())
arr = [int(x) for x in input().split()]
print(No_Books(arr,n))
Output
5
4 5 5 2 4
6
Here minimum moves required is 6
I'm interpreting the question in the following way:
For each element in the array, there is one and only one operation you're allowed to perform, and that operation is to replace an index's value with the array's current second-largest element.
How many operations are necessary to make the entire array's values equal to the initial minimum value?
With the example input 4 5 5 2 4 needing to go through the following steps:
Array - step - comments
4 5 5 2 4 - 0 - start
4 4 5 2 4 - 1 - replace the first 5 with 4 (the second-largest value in the array)
4 4 4 2 4 - 2 - replace the second 5 with 4
2 4 4 2 4 - 3 - replace the first 4 with 2
2 2 4 2 4 - 4
2 2 2 2 4 - 5
2 2 2 2 2 - 6
It took 6 steps, so the result is 6.
If that is correct, then I can change your quadratic solution (O(n^2), where n is the size of the array) to a quasilinear solution (O(n + mlogm) where n is the size of the array, and m is the number of unique values in the array), as follows.
The approach is to notice that each value needs to be dropped down to the next largest value for each unique value smaller than itself. So if we can track the count of each unique value, we can determine the number of steps without actually doing any array updates.
In pseudocode:
function determineSteps(array):
define map from integer to integer, defaulting to 0
for each value in array: // Linear in N
map(value)++
sort map by key, descending // M log M
// largerCount is the number of elements larger than the current second-largest value
define largerCount, assign 0 to largerCount
// stepCount is the number of steps required
define stepCount, assign 0 to stepCount
for each key in map except the last: // Linear in M
largerCount = largerCount + map(key)
stepCount = stepCount + largerCount
return stepCount
On your example input:
4 5 5 2 4
Create map { 4: 2, 5: 2, 2: 1 }
Sort map by key, descending: { 5: 2, 4: 2, 2: 1 }
stepCount = 0
largerCount = 0
Examine key = 5, map(key) = 2
largerCount = 0 + 2 = 2
stepCount = 0 + 2 = 2
Examine key = 4, map(key) = 2
largerCount = 2 + 2 = 4
stepCount = 2 + 4 = 6
return 6

How to change a certain count of numpy matrix elements?

I have a square numpy 2D matrix.
2 2 2 2
2 2 2 2
2 2 2 2
2 2 2 2
And I need to set a certain count of random matrix values to 0. Let's say it is 5 elements. That means any 5 from 16 matrix values must be set to 0. For example new matrix could be
2 2 0 0
0 2 2 2
2 2 2 2
0 2 0 2
or
2 0 2 2
2 2 0 2
2 2 0 2
0 2 2 0
or some else.
How could I do this efficient way?
This will do it:
import random
arr1d = arr.ravel()
randidx = random.sample(range(len(arr1d)), 5)
arr1d[randidx] = 0
This modifies arr because ravel() returns a view, not a copy.
For more on how the random numbers can be generated, see: Non-repetitive random number in numpy
lets say your matrix is "matrix"
import random
for i in range(5):
random1=random.randint(0,size_x_ofmatrix)
random2=random.randint(0,size_y_ofmatrix)
matrix[random1,random2]=0

Shuffle "coupled" elements in python array

Let's say I have this array:
np.arange(9)
[0 1 2 3 4 5 6 7 8]
I would like to shuffle the elements with np.random.shuffle but certain numbers have to be in the original order.
I want that 0, 1, 2 have the original order.
I want that 3, 4, 5 have the original order.
And I want that 6, 7, 8 have the original order.
The number of elements in the array would be multiple of 3.
For example, some possible outputs would be:
[ 3 4 5 0 1 2 6 7 8]
[ 0 1 2 6 7 8 3 4 5]
But this one:
[2 1 0 3 4 5 6 7 8]
Would not be valid because 0, 1, 2 are not in the original order
I think that maybe zip() could be useful here, but I'm not sure.
Short solution using numpy.random.shuffle and numpy.ndarray.flatten functions:
arr = np.arange(9)
arr_reshaped = arr.reshape((3,3)) # reshaping the input array to size 3x3
np.random.shuffle(arr_reshaped)
result = arr_reshaped.flatten()
print(result)
One of possible random results:
[3 4 5 0 1 2 6 7 8]
Naive approach:
num_indices = len(array_to_shuffle) // 3 # use normal / in python 2
indices = np.arange(num_indices)
np.random.shuffle(indices)
shuffled_array = np.empty_like(array_to_shuffle)
cur_idx = 0
for idx in indices:
shuffled_array[cur_idx:cur_idx+3] = array_to_shuffle[idx*3:(idx+1)*3]
cur_idx += 3
Faster (and cleaner) option:
num_indices = len(array_to_shuffle) // 3 # use normal / in python 2
indices = np.arange(num_indices)
np.random.shuffle(indices)
tmp = array_to_shuffle.reshape([-1,3])
tmp = tmp[indices,:]
tmp.reshape([-1])

Python random function to select a new item from a list of values

I need to fetch random numbers from a list of values in Python. I tried using random.choice() function but it sometimes returns same values consecutively. I want to return new random values from the list each time. Is there any function in Python that allows me to perform such an action ?
Create a copy of the list, shuffle it, then pop items from that one by one as you need a new random value:
shuffled = origlist[:]
random.shuffle(shuffled)
def produce_random_value():
return shuffled.pop()
This is guaranteed to not repeat elements. You can, however, run out of numbers to pick, at which point you could copy again and re-shuffle.
To do this continuously, you could make this a generator function:
def produce_randomly_from(items):
while True:
shuffled = list(items)
random.shuffle(shuffled)
while shuffled:
yield shuffled.pop()
then use this in a loop or grab a new value with the next() function:
random_items = produce_randomly_from(inputsequence)
# grab one random value from the sequence
random_item = next(random_items)
Here is an example:
>>> random.sample(range(10), 10)
[9, 5, 2, 0, 6, 3, 1, 8, 7, 4]
Just replace the sequence given by range with the one you want to choose from. The second number is how many samples, and should be the length of the input sequence.
If you just want to avoid consecutive random values, you can try this:
import random
def nonrepeating_rand(n):
''' Generate random numbers in [0, n) such that no two consecutive numbers are equal. '''
k = random.randrange(n)
while 1:
yield k
k2 = random.randrange(n-1)
if k2 >= k: # Skip over the previous number
k2 += 1
k = k2
Test:
for i,j in zip(range(25), nonrepeating_rand(3)):
print i,j
prints (for example)
0 1
1 0
2 2
3 0
4 2
5 0
6 2
7 1
8 0
9 1
10 0
11 2
12 0
13 1
14 0
15 2
16 1
17 0
18 2
19 1
20 0
21 2
22 1
23 2
24 0
You can use nonrepeating_rand(len(your_list)) to get random indices for your list.

Categories

Resources