joeschmidt45
joeschmidt45

Reputation: 1962

How to perform an operation on every two columns of a numpy array?

Right now I have a NumPy array of 0's and 1's and I want to perform a logical_and on every two columns. A for loop achieving this would look as follows:

import numpy as np
result = []
data = [[0, 1, 1],
        [1, 0, 1],
        [1, 0, 1]]
np_data = np.array(data)
num_cols = len(np_data[1,:])
for i in range(0, num_cols):
    for j in range(i+1, num_cols):
        #Comparing every column with every other column
        anded = np.logical_and(np_data[:,i], np_data[:,j])
        result.append(anded)
print result

I was just wondering whether there was a NumPy-fied way to do this since obviously for loops are not good for operating on NumPy arrays.

Upvotes: 2

Views: 1298

Answers (3)

Johan Lundberg
Johan Lundberg

Reputation: 27028

I'm sure there's a smarter way to construct the index lists ii,jj but this does the same as your code for your example:

import numpy as np
data = [[0, 1, 1],
       [1, 0, 1],
       [1, 0, 1]]
np_data = np.array(data)
q=range(len(data))
ii,jj=zip(*[[i,j] for i in q for j in q if i<j])
result=np.transpose(np.logical_and(np_data[:,list(ii)],np_data[:,list(jj)]))

Edit: for ii,jj you can also use this (inspired by Bago):

ii,jj = np.array(list(combinations(q, 2))).T

Upvotes: 0

steabert
steabert

Reputation: 6878

Assume you have an array (n,m) with n rows and m columns, then you can get the logical and between all possible columns as an array (m,m) where each element is an array of size n. This is similar to your result, but double the size (no triangular matrix).

import numpy as np
data = np.array([[0, 1, 1],
                 [1, 0, 1],
                 [1, 0, 1]])
n,m = data.shape
dist0 = np.tile(data.T,(m,1)).reshape(m,m,n) # repeat columns along axis 0
dist1 = np.tile(data.T,(1,m)).reshape(m,m,n) # repeat columns along axis 1
result = np.logical_and(dist0, dist1)
# now result[i,j] contains the logical_and bewteen column i and j
print(result[0,2])
[False  True  True]

Upvotes: 0

Bi Rico
Bi Rico

Reputation: 25823

You can do it like this, notice that result is the transpose of your result (Also in this case result is a 2d array and in your case it is a list of 1darrays).

>>> from itertools import combinations
>>> I, J = np.array(list(combinations([0,1,2], 2))).T
>>> result = np.logical_and(np_data[:, I], np_data[:, J])
>>> result
array([[False, False,  True],
       [False,  True, False],
       [False,  True, False]], dtype=bool)
>>> result.T
array([[False, False, False],
       [False,  True,  True],
       [ True, False, False]], dtype=bool)

Upvotes: 1

Related Questions