Home > other >  How to replace unique value with True and other values with False in Tensor.tensorflow?
How to replace unique value with True and other values with False in Tensor.tensorflow?

Time:08-26

Summary

I am looking for a function is_unique that for each element in a tensorflow tf.Tensor returns a boolean value whether its value is unique within the tensor.

Example input / output:

In [7]: idx = tf.constant([162, 223, 276, 162, 261, 215,   0,   0,   0], dtype=tf.int64)
In [8]: is_unique(idx)
Out[8]: <tf.*Tensor*: shape=(9,), dtype=bool, numpy=array([False,  True,  True, False,  True,  True, False, False, False])>

Adding another example on request for a tensor with higher rank: For a rank-2 tensor

tf.constant([[1, 2], [1, 3]], dtype=tf.int32) 

the function would yield

<tf.Tensor: shape=(2, 2), dtype=bool, numpy=
array([[False,  True],
       [False,  True]])>

This seems to be rather basic, but I believe there is no such function in tensorflow, or is there?

My code:

I haven't found a simple way to achieve this with tf.unique et al., so my current implementation looks like this:

def is_unique(t):
    return tf.equal(
        tf.reduce_sum(
            tf.cast(
                t[:,tf.newaxis] == t,
                tf.int64,
            ),
        axis = 1
        ),
        1
    )

(Basically, this creates a matrix of comparisons of every element with every other, counts the number of positive outcomes per row and compares this with 1.)

This won't work with tensors of rank > 1 and needs quadratic memory in the tensor size, so feel free to propose better solutions.

CodePudding user response:

Rank 1 solution, although very similar to yours:

import tensorflow as tf

x = tf.constant([162, 223, 276, 162, 261, 215,   0,   0,   0], dtype=tf.int64)
y, _, count = tf.unique_with_counts(x)
x = tf.reduce_all(tf.where(x == tf.gather(y, tf.where(count > 1)), False, True), axis=0)
tf.Tensor([False  True  True False  True  True False False False], shape=(9,), dtype=bool)

Rank 2 solution (see improved version @I'mahdi)

CodePudding user response:

You can use tensorflow.unique_with_counts and tf.math.reduce_any

For rank==1:

import tensorflow as tf
x = tf.constant([162, 223, 276, 162, 261, 215,   0,   0,   0], dtype=tf.int64)
y, _, count = tf.unique_with_counts(x)
res = tf.reduce_any(x[:, None] == y[count < 2], axis=1)
print(res)
# tf.Tensor([False  True  True False  True  True False False False], shape=(9,), dtype=bool)

For rank==2:

x = tf.constant([[1, 2], 
                 [1, 3],
                 [4, 3]], dtype=tf.int32) # 2 & 4 are unique

y, _, count = tf.unique_with_counts(tf.experimental.numpy.ravel(x))
res = tf.reduce_any(x[..., None] == y[count < 2], axis=2)
print(res)

# tf.Tensor(
# [[False  True]
#  [False False]
#  [ True False]], shape=(3, 2), dtype=bool)

For another Input:

x = tf.constant([[1, 2], 
                 [1, 3], 
                 [3, 1]], dtype=tf.int32) # 2 is unique

y, _, count = tf.unique_with_counts(tf.experimental.numpy.ravel(x))
res = tf.reduce_any(x[..., None] == y[count < 2], axis=2)
print(res)

# tf.Tensor(
# [[False  True]
#  [False False]
#  [False False]], shape=(3, 2), dtype=bool)
  • Related