7

I've just started to learn about Python libraries and today I got stuck at a numpy exercise.

Let's say I want to generate a 5x5 random array whose values are all different from each other. Further, its values have to range from 0 to 100.

I have already look this up here but found no suitable solution to my problem. Please see the posts I consulted before turning to you:

Here is my attempt to solve the exercise:

import numpy as np

M = np.random.randint(1, 101, size=25)
for x in M:
    for y in M:
        if x in M == y in M:
            M = np.random.randint(1, 101, size=25)
            print(M)

By doing this, all I get is a value error: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Thus, my second attempt has been the following:

M = np.random.randint(1, 101, size=25)
a = M[x]
b = M[y]

for a.any in M:
    for b.any in M:
        if a.any in M == b.any in M:
            M = np.random.randint(1, 101, size=25)
            print(M)

Once again, I got an error: AttributeError: 'numpy.int64' object attribute 'any' is read-only.

Could you please let me know what am I doing wrong? I've spent days going over this but nothing else comes to mind :(

Thank you so much!

5
  • np.random.random((5,5))*100 Commented Nov 13, 2021 at 17:36
  • Focus on the test line - the if. That's what's giving the problem. Look at the M==y step. Does it make sense to do an if test on that? Commented Nov 13, 2021 at 18:06
  • What's wrong with choice? You are going at it the hard way, repeatedly creating the array of values until one meets the criteria. Let numpy do the work for you. Commented Nov 13, 2021 at 19:22
  • When the error message tells you to use any, it means (M == b).any(). any is boolean operation, meant to work with an array of True/False values. Application to a number doesn't make sense (as in a.any()). Commented Nov 13, 2021 at 19:36
  • Thanks a lot for your insights @hpaulj, Now I've got a better understanding of the any function :) Commented Nov 14, 2021 at 17:26

3 Answers 3

5

Not sure if this will be ok for all your needs, but it will work for your example:

np.random.choice(np.arange(100, dtype=np.int32), size=(5, 5), replace=False)
Sign up to request clarification or add additional context in comments.

1 Comment

choice without replacement is effectively what he wants.
1

You can use

np.random.random((5,5))

to generate an array of random numbers from 0 to 1, with shape (5,5).

Then just multiply by 100 to get the numbers between 0 and 100:

100*np.random.random((5,5))

Your code gives an error because of this line:

if x in M == y in M:

That syntax doesn't work. And M == y is a comparison between an array and a number, which is why you get ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().

You already defined x and y as elements of M in the for loops so just write

if x == y:

Comments

1

While I think choice without replacement is the easy way to go, here's a way implementing your approach. I use np.unique to test whether all the numbers are different.

In [158]: M = np.random.randint(1,101, size=25)
In [159]: x = np.unique(M)
In [160]: x.shape
Out[160]: (23,)
In [161]: cnt = 1
     ...: while x.shape[0]<25:
     ...:     M = np.random.randint(1,101,size=25)
     ...:     x = np.unique(M)
     ...:     cnt += 1
     ...: 
In [162]: cnt
Out[162]: 34
In [163]: M
Out[163]: 
array([ 70,  76,  27,  98,  81,  92,  97,  38,  49,   7,   2,  55,  85,
        89,  32,  51,  20, 100,   9,  91,  53,   3,  11,  63,  21])

Note that I had to generate 34 random sets before I got a unique one. That is a lot of work!

unique works by sorting the array, and then looking for adjacent duplicates.

A numpy whole-array approach to testing whether there are any duplicates is:

For this unique set:

In [165]: (M[:,None]==M).sum(axis=0)
Out[165]: 
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

but for another randint array:

In [166]: M1 = np.random.randint(1,101, size=25)
In [168]: (M1[:,None]==M1).sum(axis=0)
Out[168]: 
array([1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,  2, 2, 1])

This M[:,None]==M is roughly the equivalent of

for x in M:
    for y in M:
        test x==y

I'm using sum to count how many True values there are in each column. any just identifies if there is a True.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.