How to create random pairs from list - python

I am trying to create 8 random pairs from a list of from given 10 images.
import random
imageList = ['1.jpg','2.jpg','3.jpg','4.jpg','5.jpg','6.jpg','7.jpg','8.jpg','9.jpg','10.jpg']
for i in range(len(imageList)):
imagepair = range(len(imageList) - 1)

You can simply shuffle the list, then take the first 4 items from it, and repeat once more:
for _ in range(2):
random.shuffle(imageList)
i=0
while(i<8):
print(imageList[i], imageList[i+1])
i+=2

You can use random.shuffle and create a generator to get samples of image groups as many times as needed.
def image_generator(l):
while True:
random.shuffle(l)
yield l[:2]
for i in range(8):
print(next(image_generator(imageList)))
['6.jpg', '2.jpg']
['10.jpg', '5.jpg']
['8.jpg', '6.jpg']
['6.jpg', '1.jpg']
['5.jpg', '3.jpg']
['8.jpg', '6.jpg']
['6.jpg', '2.jpg']
['8.jpg', '2.jpg']
Another way is you can use itertools.product to get permutations of n (or 2) for images, filtering out cases where both images are the same. And then you can use random.sample to get 8 samples.
import random
import itertools
def image_generator(iterable, groups, samplesize):
grouped = (i for i in itertools.product(imageList,repeat=2) if i[0]!=i[1])
return random.sample(list(grouped), samplesize)
image_generator(imageList, 2, 8)
[('8.jpg', '7.jpg'),
('7.jpg', '10.jpg'),
('7.jpg', '2.jpg'),
('6.jpg', '7.jpg'),
('5.jpg', '3.jpg'),
('2.jpg', '1.jpg'),
('10.jpg', '5.jpg'),
('9.jpg', '10.jpg')]

use random function to get 2 integers as index values and pair the corresponding image.

Related

How to create a list with random integers

I am trying to create a random list of 1 million numbers ranging between 1-100. I have found how to create a single random number but not to create a list of them. In addition, I would prefer to use the numpy uniform function but the solution doesn't have to use this.
For a big array, you'd better use numpy
import numpy as np
X = np.random.randint(1, 101, size=10**6)
Try this simpler one :
from random import randint
my_list = [randint(1, 100) for i in range(1000000)]
The function
np.random.rand(Dim1,Dim2)
will create an array for the given dimensions with values selected from the uniform distribution [0,1]. You can modify this to randomArray = 1 + 99 * np.random.rand(Dim1,Dim2) to have the array with numbers ranging between 1-100.
from random import *
mylist = []
for i in range(0, 100):
f = randint(0, 100)
mylist.insert(i, f)
This code will give 100 random elements to your empty list.
use this as simple as that...don't make your program more complex in code and in efficiency too..
from random import randint
l=[randint(1,100) for i in range(0,1000000)]

How do I make an iteration of random numbers in Python 3?

I made a random number with this:
import random
number = random.randrange(0,100,2)
I want to iterate in it:
for i in number:
print(i)
or like that:
for number in range (50,100):
print number
I want to make a lists of random numbers, for example 50 random numbers between 0 and 100.
generate a sorted list of 50 different random numbers between 0 and 100 (not included) like this:
sorted(random.sample(range(0,100),50))
(pick 50 elements in the range object and sort them)
If you need/want repeats don't use sample just pick 50 numbers
sorted([random.randrange(0,100) for _ in range(50)])
or from python 3.6: sorted(random.choices(range(100),k=50))
For generating a list with n random numbers, you can use list comprehension. Such as,
lst = [random.randint(0,100) for _ in range(n)]
If you want to make a list of 50 random numbers between 1 and 100, you can do this:
import random
randlist = []
for i in range(50):
randlist += [random.randint(1, 100)]

varying degree of shuffling using random module python

I am using two architecture programs, with visual programming plugins (Grasshopper for Rhino and Dynamo for Revit - for those that know / are interested)
Grasshopper contains a function called 'Jitter' this will shuffle a list, however it has an input from 0.0 to 1.0 which controls the degree of shuffling - 0.0 results in no shuffling 1.0 produces a complete shuffle.
The second of the programs (Dynamo) does not contain this functionality. It contains a shuffle module (which contains a seed value) however it is a complete random shuffle.
Ultimately the goal is to produce a series of solid and glazed panels, but to produce a slight random effect (but avoiding large clumping of solid and glazed elements - hence I want a "light shuffle")
I have written a code which will calculate the number of glazed(True) and solid(False) values required and then evenly distribute True and False values based on the number of items and percent specified.
I have checked out the random module reference however I'm not familiar with the various distributions as described.
Could someone help out or point me in the right direction if an existing function would achieve this.
(I have cheated slightly by adding True False alternately to make up the correct number of items within the list - list3 is the final list, list2 contains the repeated module of true falses)
Many thanks
import math
import random
percent = 30
items = 42
def remainder():
remain = items % len(list2)
list3.append(True)
remain -= 1
while remain > 0 :
list3.append(False)
remain -= 1
return list3
#find module of repeating True and False values
list1 = ([True] + [False] * int((100/percent)-1))
#multiply this list to nearest multiple based on len(items)
list2 = list1 * int(items/(100/percent))
# make a copy of list2
list3 = list2[:]
#add alternating true and false to match len(list3) to len(items)
remainder()
#an example of a completely shuffled list - which is not desired
shuffled = random.sample(list3, k = len(list3))
Here is an approach based on this paper which proves a result about the mixing time needed to scramble a list by using swaps of adjacent items
from random import choice
from math import log
def jitter(items,percent):
n = len(items)
m = (n**2 * log(n))
items = items[:]
indices = list(range(n-1))
for i in range(int(percent*m)):
j = choice(indices)
items[j],items[j+1] = items[j+1],items[j]
return items
A test, each line showing the result of jitter with various percents being applied to the same list:
ls = list(('0'*20 + '1'*20)*2)
for i in range(11):
p = i/10.0
print(''.join(jitter(ls,p)))
Typical output:
00000000000000000000111111111111111111110000000000000000000011111111111111111111
00000000000000111100001101111011011111001010000100010001101000110110111111111111
00000000100100000101111110000110111101000001110001101001010101100011111111111110
00000001010010011011000100111010101100001111011100100000111010110111011001011111
00100001100000001101010000011010011011111011001100000111011011111011010101011101
00000000011101000110000110000010011001010110011111100100111101111011101100111110
00110000000001011001000010110011111101001111001001100101010011010111111011101100
01101100000100100110000011011000001101111111010100000100000110111011110011011111
01100010110100010100010100011000000001000101100011111011111011111011010100011111
10011100101000100010001100100000100111001111011011000100101101101010101101011111
10000000001000111101101011000011010010110011010101110011010100101101011110101110
I'm not sure how principled the above is, but it seems like a reasonable place to start.
There's no clear definition of what "degree of shuffling" (d) means, so you'll need to choose one. One option would be: "the fraction of items remaining unshuffled is (1-d)".
You could implement that as:
Produce a list of indices
Remove (1-d)*N of them
Shuffle the rest
Reinsert the ones removed
Use these to look up values from the original data
def partial_shuffle(x, d):
"""
x: data to shuffle
d: fraction of data to leave unshuffled
"""
n = len(x)
dn = int(d*n)
indices = list(range(n))
random.shuffle(indices)
ind_fixed, ind_shuff = indices[dn:], indices[:dn]
# copy across the fixed values
result = x[:]
# shuffle the shuffled values
for src, dest in zip(ind_shuff, sorted(ind_shuff)):
result[dest] = x[src]
return result
The other algorithms you're referring to are probably using the Fisher-Yates shuffle under the hood.
This O(n) shuffle starts with the first element of an array and swaps it with a random higher element, then swaps the second element with a random higher element, and so on.
Naturally, stopping this shuffle before you reach the last element at some fraction [0,1] would give a partially-randomized array, like you want.
Unfortunately, the effect of the foregoing is that all the "randomness" builds up on one side of the array.
Therefore, make a list of array indices, shuffle these completely, and then use the indices as an input to the Fisher-Yates algorithm to partially sort the original array.
I believe I found a more versatile, robust, and a consistent way to implement this "adjustable shuffling" technique.
import random
import numpy as np
def acc_shuffle(lis, sr, array=False, exc=None): # "sr" = shuffling rate
if type(lis) != list: # Make it compatible with shuffling (mxn) numpy.ndarrays
arr = lis
shape = arr.shape
lis = list(arr.reshape(-1))
lis = lis[:] # Done, such that any changes applied on "lis" wont affect original input list "x"
indices = list(range(len(lis)))
if exc is not None: # Exclude any indices if necessary
for ele in sorted(exc, reverse=True):
del indices[ele]
shuff_range = int(sr * len(lis) / 2) # How much to shuffle (depends on shuffling rate)
if shuff_range < 1:
shuff_range = 1 # "At least one shuffle (swap 2 elements)"
for _ in range(shuff_range):
i = random.choice(indices)
indices.remove(i) # You can opt not to remove the indices for more flexibility
j = random.choice(indices)
indices.remove(j)
temp = lis[i]
lis[i] = lis[j]
lis[j] = temp
if array is True:
return np.array(lis).reshape(shape)
return lis

How to delete random items in a list to keep the list in a certain length?

I used pymongo to dump a list of collections in MongoDB. The length of the list is greater than 10000, about 12000 or longer(The length of the list is not a certain number).
However, I need only 10000 instances of the list. I know that a list 'l' is able to slice by l[:10000] or l[len(l)-10000:]. But I think maybe a random way to delete the item in a list is better.
So I want to know how can I delete random items in the list to make its length reduce to 10000 long? Thanks.
Shuffle the list first and then slice it:
from random import shuffle
shuffle(your_lis)
your_lis = your_lis[:10000]
If order matters:
from random import randrange
diff = len(your_lis) - 10000
for _ in xrange(diff):
ind = randrange(len(your_lis))
your_lis.pop(ind) #a quick timing check suggests that `pop` is faster than `del`
If you want to keep order, you can remove random indexes, for instance:
def remove_random(l, count):
for i in range(count):
index = random.randint(0, len(l) - 1)
del l[index]
This function will remove up to count items from list l.
Here is another way:
from random import random
def chop(the_list, length):
while len(the_list) > length:
del the_list[int(random()*length)]
# usage
chop(your_list, 10000)
def random_reduce(list, count):
length = len(l)
for i in range(count):
index = random.randint(0, length - 1)
del list[index]
length = length - 1
It is quite straightforward using numpy (only extracting 4 items for readability):
>>> import numpy as np
>>> l = range(0, 12000)
>>> np.random.choice(np.asarray(l), 4, false)
import random
subsample=random.sample(population,k)

Pick N distinct items at random from sequence of unknown length, in only one iteration

I am trying to write an algorithm that would pick N distinct items from an sequence at random, without knowing the size of the sequence in advance, and where it is expensive to iterate over the sequence more than once. For example, the elements of the sequence might be the lines of a huge file.
I have found a solution when N=1 (that is, "pick exactly one element at random from a huge sequence"):
import random
items = range(1, 10) # Imagine this is a huge sequence of unknown length
count = 1
selected = None
for item in items:
if random.random() * count < 1:
selected = item
count += 1
But how can I achieve the same thing for other values of N (say, N=3)?
If your sequence is short enough that reading it into memory and randomly sorting it is acceptable, then a straightforward approach would be to just use random.shuffle:
import random
arr=[1,2,3,4]
# In-place shuffle
random.shuffle(arr)
# Take the first 2 elements of the now randomized array
print arr[0:2]
[1, 3]
Depending upon the type of your sequence, you may need to convert it to a list by calling list(your_sequence) on it, but this will work regardless of the types of the objects in your sequence.
Naturally, if you can't fit your sequence into memory or the memory or CPU requirements of this approach are too high for you, you will need to use a different solution.
Use reservoir sampling. It's a very simple algorithm that works for any N.
Here is one Python implementation, and here is another.
Simplest I've found is this answer in SO, improved a bit below:
import random
my_list = [1, 2, 3, 4, 5]
how_big = 2
new_list = random.sample(my_list, how_big)
# To preserve the order of the list, you could do:
randIndex = random.sample(range(len(my_list)), how_big)
randIndex.sort()
new_list = [my_list[i] for i in randIndex]
If you have python version of 3.6+ you can use choices
from random import choices
items = range(1, 10)
new_items = choices(items, k = 3)
print(new_items)
[6, 3, 1]
#NPE is correct, but the implementations that are being linked to are sub-optimal and not very "pythonic". Here's a better implementation:
def sample(iterator, k):
"""
Samples k elements from an iterable object.
:param iterator: an object that is iterable
:param k: the number of items to sample
"""
# fill the reservoir to start
result = [next(iterator) for _ in range(k)]
n = k - 1
for item in iterator:
n += 1
s = random.randint(0, n)
if s < k:
result[s] = item
return result
Edit As #panda-34 pointed out the original version was flawed, but not because I was using randint vs randrange. The issue is that my initial value for n didn't account for the fact that randint is inclusive on both ends of the range. Taking this into account fixes the issue. (Note: you could also use randrange since it's inclusive on the minimum value and exclusive on the maximum value.)
Following will give you N random items from an array X
import random
list(map(lambda _: random.choice(X), range(N)))
It should be enough to accept or reject each new item just once, and, if you accept it, throw out a randomly chosen old item.
Suppose you have selected N items of K at random and you see a (K+1)th item. Accept it with probability N/(K+1) and its probabilities are OK. The current items got in with probability N/K, and get thrown out with probability (N/(K+1))(1/N) = 1/(K+1) so survive through with probability (N/K)(K/(K+1)) = N/(K+1) so their probabilities are OK too.
And yes I see somebody has pointed you to reservoir sampling - this is one explanation of how that works.
As aix mentioned reservoir sampling works. Another option is generate a random number for every number you see and select the top k numbers.
To do it iteratively, maintain a heap of k (random number, number) pairs and whenever you see a new number insert to the heap if it is greater than smallest value in the heap.
This was my answer to a duplicate question (closed before I could post) that was somewhat related ("generating random numbers without any duplicates"). Since, it is a different approach than the other answers, I'll leave it here in case it provides additional insight.
from random import randint
random_nums = []
N = # whatever number of random numbers you want
r = # lower bound of number range
R = # upper bound of number range
x = 0
while x < N:
random_num = randint(r, R) # inclusive range
if random_num in random_nums:
continue
else:
random_nums.append(random_num)
x += 1
The reason for the while loop over the for loop is that it allows for easier implementation of non-skipping in random generation (i.e. if you get 3 duplicates, you won't get N-3 numbers).
There's one implementation from the numpy library.
Assuming that N is smaller than the length of the array, you'd have to do the following:
# my_array is the array to be sampled from
assert N <= len(my_array)
indices = np.random.permutation(N) # Generates shuffled indices from 0 to N-1
sampled_array = my_array[indices]
If you need to sample the whole array and not just the first N positions, then you can use:
import random
sampled_array = my_array[random.sample(len(my_array), N)]

Categories

Resources