user42493
user42493

Reputation: 1103

How to generate a matrix as follows?

So given number n and an array a, we need to create a n by len(a) matrix where the i,jth entry of the matrix is 1 if i equals to jth entry of a and -1 otherwise. Namely for each numbers i from 0 to n-1, we need to have an array that tell us if the number i is equal to the array a.

It would be cool if we had map feature like in functional programming. Then I could just create the rows by checking for each elements in array a if that element equals the given number or not.

So is there a feature that I can use as shown below?

result=[]
for i in range(n):
    result=np.vstack(result, np.map(checkequals(x,i),a)
return result

Upvotes: 0

Views: 50

Answers (2)

hpaulj
hpaulj

Reputation: 231385

Generally a functional or mapping approach is not optimal with numpy. numpy is all about arrays, so it's best to think in terms of the whole-array building blocks that numpy provides. Those operate in compiled code.

For example with your case:

Define an array:

In [10]: a = np.random.randint(0,10,9)                                          
In [11]: a                                                                      
Out[11]: array([6, 0, 2, 5, 0, 5, 2, 0, 1])

Compare it with the range of n values - using whole array == test (and broadcasting. The result is a boolean array, a True/False value for each (i,j):

In [12]: np.arange(8)[:,None]==a                                                
Out[12]: 
array([[False,  True, False, False,  True, False, False,  True, False],
       [False, False, False, False, False, False, False, False,  True],
       [False, False,  True, False, False, False,  True, False, False],
       [False, False, False, False, False, False, False, False, False],
       [False, False, False, False, False, False, False, False, False],
       [False, False, False,  True, False,  True, False, False, False],
       [ True, False, False, False, False, False, False, False, False],
       [False, False, False, False, False, False, False, False, False]])

Given that, it's easy to map it onto a (-1,1) values. np.where is just one such way:

In [13]: np.where(np.arange(8)[:,None]==a, 1, -1)                               
Out[13]: 
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, -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,  1, -1, -1, -1],
       [ 1, -1, -1, -1, -1, -1, -1, -1, -1],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1]])

Closer to your map idea, we could define a function that operates on a pair of scalar values:

def foo(i,x):
    if i==x:
        return 1
    else:
        return -1

and use np.vectorize to make a function that takes 2 arrays, and passes pairs of scalars to this function.

In [16]: np.vectorize(foo)(np.arange(8)[:,None], a)                              
Out[16]: 
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, -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,  1, -1, -1, -1],
       [ 1, -1, -1, -1, -1, -1, -1, -1, -1],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1]])

But this is MUCH slower than the first approach.

A list comprehension approach:

In [22]: [[(1 if i==x else -1) for x in a] for i in range(8)]                   
Out[22]: 
[[-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, -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, 1, -1, -1, -1],
 [1, -1, -1, -1, -1, -1, -1, -1, -1],
 [-1, -1, -1, -1, -1, -1, -1, -1, -1]]

which can then be made into an array (this may actually be faster than the vectorize approach).

Upvotes: 1

MCI
MCI

Reputation: 922

Python2 has a built in map function, and so does python3. Numpy has vectorize

Upvotes: 0

Related Questions