35

I want to do something like this.
Let's say we have a tensor A.

A = [[1,0],[0,4]]

And I want to get nonzero values and their indices from it.

Nonzero values: [1,4]  
Nonzero indices: [[0,0],[1,1]]

There are similar operations in Numpy.
np.flatnonzero(A) return indices that are non-zero in the flattened A.
x.ravel()[np.flatnonzero(x)] extract elements according to non-zero indices.
Here's a link for these operations.

How can I do somthing like above Numpy operations in Tensorflow with python?
(Whether a matrix is flattened or not doesn't really matter.)

ByungSoo Ko
  • 503
  • 1
  • 6
  • 7

3 Answers3

50

You can achieve same result in Tensorflow using not_equal and where methods.

zero = tf.constant(0, dtype=tf.float32)
where = tf.not_equal(A, zero)

where is a tensor of the same shape as A holding True or False, in the following case

[[True, False],
 [False, True]]

This would be sufficient to select zero or non-zero elements from A. If you want to obtain indices you can use wheremethod as follows:

indices = tf.where(where)

where tensor has two True values so indices tensor will have two entries. where tensor has rank of two, so entries will have two indices:

[[0, 0],
 [1, 1]]
Sergii Gryshkevych
  • 4,029
  • 1
  • 25
  • 42
  • How will you get the array from the boolean matrix? I dont think boolean indexing is implemented yet – martianwars Jan 07 '17 at 04:08
  • 1
    @martianwars see the link to `where` documentation. It accepts booleans and produces a tensor of corresponding indices. – Sergii Gryshkevych Jan 07 '17 at 12:49
  • 1
    No I meant the values at those indices. I did it using a boolean mask – martianwars Jan 07 '17 at 12:58
  • How can you get just the indices of the rows which are completely zero ? – Qubix Jan 23 '17 at 13:16
  • Define `zero` tensor as a tensor of zeros with the same shape as your row. For example, use [`zeros_like`](https://www.tensorflow.org/api_docs/python/constant_op/constant_value_tensors#zeros_like) to define it @Qubix – Sergii Gryshkevych Jan 23 '17 at 13:25
  • @SergiiGryshkevych I tried this, using `tf.zeros()` of 1x4 and using `tf.not_equal()` between that vector, and a 200x4 tensor. The result was matrix of 200x4 of the comparison of every element to zero, and not vectors... – bluesummers Jun 25 '17 at 08:08
  • 1
    re "And I want to get nonzero values" Please show how to get the values at those indices. Thank you – Geoffrey Anderson Apr 18 '18 at 16:52
6
#assume that an array has 0, 3.069711,  3.167817.
mask = tf.greater(array, 0)
non_zero_array = tf.boolean_mask(array, mask)
user1098761
  • 579
  • 1
  • 5
  • 16
0

What about using sparse tensors.

>>> A = [[1,0],[0,4]]
>>> sparse = tf.sparse.from_dense(A)
>>> sparse.values.numpy(), sparse.indices.numpy()
(array([1, 4], dtype=int32), array([[0, 0],
        [1, 1]]))
  • This is a good answer for actual sparse tensors, but I have the feeling this could be inefficient for dense tensors. I can well imagine, that there are memory overheads from the conversion to the sparse tensor. Personally, I would use Sergii's answer, since it is more transparent. – André Mar 30 '22 at 08:20
  • 1
    @André, good point. I took a look to the [implementation](https://github.com/tensorflow/tensorflow/blob/v2.8.0/tensorflow/python/ops/sparse_ops.py#L102-L131) and is very similar to Sergii's suggestion. ```python indices = tf.where_v2(tf.not_equal(A, tf.zeros_like(A))) values = array_ops.gather_nd(A, indices) ``` – Ricardo Zilleruelo Ramos Mar 30 '22 at 17:34