Find all unique neighbor pairs between segments of ndimage labeling in an efficient manner - python

Below I give an example in 2D, but my real question would be regarding 3D (with or without periodic boundaries). Find all unique neighbors for each segment id using 8 neighbors (2d) or 26 neighbors (3d).
Given the following array:
INPUT
matrix=[
[1, 2, 2, 3],
[1, 4, 5, 3],
[4, 4, 5, 3]
]
OUTPUT non-periodic
1 : [1, 2, 4]
2 : [1, 2, 3, 4, 5]
3 : [2, 3, 5]
4 : [1, 2, 4, 5]
5 : [2, 3, 4, 5]
OUTPUT periodic
1 : [1, 2, 3, 4]
2 : [1, 2, 3, 4, 5]
3 : [1, 2, 3, 4, 5]
4 : [1, 2, 3, 4, 5]
5 : [2, 3, 4, 5]
I got a stack of for loops to do the job, but I would really like to use a more numpy/scipy based approach if that could work. I feel like some form of clever convolve could do the trick, I am just not seeing how.
An example of such slow code is presented here.

Related

Convert lists into higher dimension so that elements can be reached by following

I have a matrix that I want to convert to 3D so that I can be able to print the element of list[i][j][k]
a = [[[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 2, 3, 4,5], [3, 2, 3, 4, 3, 4], [4, 3, 4, 5, 4, 3], [5, 4, 5, 6, 5, 4]]]
print(a[5][5][0]) # I want to be able to print in 3D`
I get right output if I do a[5][5] but wrong when I add the [0]. Is there anyway of converting my matrix such that this will be solved?
I tried to just wrap the list up with brackets [list], but it did not work. I also did:
b = [[i] for i in a]
which gave me [[[0,1,2,3,4,5]],[[1,2,3,4,5,6]],...
and it still did not work!
NOTE: I want the i to be the row, j to be the column and k to be 0 or 1, so k = 0 (in which case the value is the row index of the cell is pointing to), or the k = 1 (the value is the column index).
Tried to reproduce your issue. To me, it works if you use the right index. Here, it perfectly works if you do for instance
print(a[0][0][5]) # I want to be able to print in 3D`
for list a = [[[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [2, 3, 2, 3, 4,5], [3, 2, 3, 4, 3, 4], [4, 3, 4, 5, 4, 3], [5, 4, 5, 6, 5, 4]]] you have just a[0][n][n]. You can try a[0][5][5]
You have index like below:
a = [
#0 element i
[
#0 element j
[0, 1, 2, 3, 4, 5],
#1 element j
[1, 2, 3, 4, 5, 6],
#2 element j
[2, 3, 2, 3, 4,5],
#3 element j
[3, 2, 3, 4, 3, 4],
#4 element j
[4, 3, 4, 5, 4, 3],
#5 element j
[5, 4, 5, 6, 5, 4]
]
]
print(a[0][5][5]) # a[i][j][k]

Find Networkx path by a sequence of nodes

I want to find all the path that starts from a sequence of nodes, the network looks like this:
DG = nx.DiGraph()
attrs = {(1, 2), (2,3), (2,4), (4,5), (5, 6), (3,6), (6,7)}
DG.add_edges_from(attrs)
What I expect is a list of all path that starts from (1,2,3) and a list (1,2,4):
all_path = [[1, 2, 3], [1, 2, 3, 6], [1, 2, 3, 6, 7]] , [[1, 2, 4], [1, 2, 4, 5, 6], [1, 2, 4, 5, 6, 7], [1, 2, 4, 5]]
Any help would be appreciated!
There's some reading between the lines that you've left for us. For example, are you specifically looking for paths that end in node 7 in this case, or are you just looking for any path that has nowhere else to go (i.e. ends in a node of outdegree zero)? If the path contains a cycle, do we include paths that go around the cycle before ending?
My guess is that what you're really interested in is the set of all simple paths from a given node that end in a node with outdegree zero. With that in mind, here's some code you might find useful.
start = 1
ends = [n for n in DG.nodes if DG.out_degree[n] == 0]
paths = [p for e in ends
for p in nx.all_simple_paths(DG, source = start, target = e)]
print(paths)
Output: [[1, 2, 4, 5, 6, 7], [1, 2, 3, 6, 7]]
If you want paths that start from 1 and end in any other node, you could do the following.
start = 1
paths = [p for e in DG.nodes
for p in nx.all_simple_paths(DG, source = start, target = e)]
print(paths)
Output: [[1, 2], [1, 2, 4], [1, 2, 3], [1, 2, 4, 5, 6], [1, 2, 3, 6], [1, 2, 4, 5, 6, 7], [1, 2, 3, 6, 7], [1, 2, 4, 5]].
If you like, you can take this output and filter down to the paths that start with any 3 nodes. For example,
print([p for p in paths if p[:3] == [1,2,3]])
print([p for p in paths if p[:3] == [1,2,4]])
results in the outputs [[1, 2, 3], [1, 2, 3, 6], [1, 2, 3, 6, 7]] and [[1, 2, 4], [1, 2, 4, 5, 6], [1, 2, 4, 5, 6, 7], [1, 2, 4, 5]].
Alternatively, sorting paths naturally organizes the paths according to their first nodes. In particular, sorted(paths) is the list
[[1, 2],
[1, 2, 3],
[1, 2, 3, 6],
[1, 2, 3, 6, 7],
[1, 2, 4],
[1, 2, 4, 5],
[1, 2, 4, 5, 6],
[1, 2, 4, 5, 6, 7]]
which you could split into two pieces.

How can slicing dataset in TensorFlow?

I want slicing dataset in tf.data. My data is like this:
dataset = tf.data.Dataset.from_tensor_slices([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
Then the main data is:
[0 1 2 3 4]
[1 2 3 4 5]
[2 3 4 5 6]
[3 4 5 6 7]
[4 5 6 7 8]
I want create other tensor dataset that contain data like this:
[[1, 2],
[2, 3],
[3, 4],
[4, 5],
[5, 6]]
In the numpy it is like this:
dataset[:,1:3]
How can do this in TensorFlow?
Update:
I do that with this:
dataset2 = dataset.map(lambda data: data[1:3])
for val in dataset2:
print(val.numpy())
But I think there is good solutions.
According to me your solution is a best solution. For the benefit of community, i am using as_numpy_iterator() method of tf.data.Dataset to slice dataset (small syntax change to your code).
Please refer code below
import tensorflow as tf
dataset = tf.data.Dataset.from_tensor_slices([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
dataset2 = dataset.map(lambda data: data[1:3])
for val in dataset2.as_numpy_iterator():
print(val)
Output:
[1 2]
[2 3]
[3 4]
[4 5]
[5 6]

Repeat a NumPy array in multiple dimensions at once?

np.repeat(np.repeat([[1, 2, 3]], 3, axis=0), 3, axis=1)
works as expected and produces
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3]])
However,
np.repeat([[1, 2, 3]], [3, 3])
and
np.repeat([[1, 2, 3]], [3, 3], axis=0)
produce errors.
Is it possible to repeat an array in multiple dimensions at once?
First off, I think the original method you propose is totally fine. It's readable, it makes sense, and it's not very slow.
You could use the repeat method instead of function which reads a bit more nicely:
>>> x.repeat(3, 1).repeat(3, 0)
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3]])
With numpy's broadcasting rules, there's likely dozens of ways to create the repeated data and throw it around into the shape you want, too. One approach could be to use np.broadcast_to() and repeat the data in D+1 dimensions, where D is the dimension you need, and then collapse it down to D.
For example:
>>> x = np.array([[1, 2, 3]])
>>> np.broadcast_to(x.T, (3, 3, 3)).reshape((3, 9))
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3]])
And without reshaping (so that you don't need to know the final length):
>>> np.hstack(np.broadcast_to(x, (3, 3, 3)).T)
array([[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3]])
And there's likely a dozen other ways to do this. But I still think your original version is more idiomatic, as throwing it into extra dimensions to collapse it down is weird.
It isn't possible, see repeat. But you are using a array with the shape (1,3), so you have to use:
np.repeat(X, [2], axis=0)
because np.repeat(X, [2,2], axis=0) needs shape (2,3), e.g.
X = np.array([[1, 2, 3], [5, 6, 7]])
np.repeat(X, [2, 5], axis=0)
the output looks like:
[[1 2 3]
[1 2 3]
[5 6 7]
[5 6 7]
[5 6 7]
[5 6 7]]
This means [2,5] stands for [2, 5]:2x first row and [2, 5]:5x second row (shape: (2, *doesn't matter*) because axis=0 means you want to repeat the rows.
Therefore you first have to generate an array with the dimensions (3, *), and then produce the next array.
If you want to repeat your array:
np.repeat(X2, [5], axis=0)
produces:
[[1 2 3]
[1 2 3]
[1 2 3]
[1 2 3]
[1 2 3]]
because you have only a 1-dimensional array.
The first call of np.repeat produces a 2D-array, the second call duplicates the columns. If you want to use np.repeat(X2, [5], axis=0) you get the same result as you have mentioned in your post above, because you have to call np.repeat a second time on the output of np.repeat(X2, [5], axis=0).
In my opinion your use of np.repeat is the easiest and best way to achieve your output.
Edit: Hopefully the answer is now more clearly

How can I take out(or slice) the elements in a rank-2 tensor , whose first element is unique?

My title might be ambiguous due to my awkward English. But I mean this:
suppose i have a tensor a like this:
array([[1, 2, 3],
[2, 2, 3],
[2, 2, 4],
[3, 2, 3],
[4, 2, 3]], dtype=int32)
the 'first column' of this tensor could contain duplicate elements (e.g. [1, 2, 2, 3, 4] or [1, 1, 2, 3, 3, 4, 5, 5]), and which element is duplicated is not known beforehand.
and i wanna take out a tensor this:
array([[1, 2, 3],
[2, 2, 3],
[3, 2, 3],
[4, 2, 3]], dtype=int32)
as u can see, I take out the rows whose first element is a unique element in the column of a.
I first wanted to use the function tf.unique() . BUT the idx value returned by it doesn't indicate the first index of each value of output tensor in the original tensor.
tf.unique() works like this:
# tensor 'x' is [1, 1, 2, 3, 3, 3, 7, 8, 8]
y, idx = tf.unique(x)
y ==> [1, 2, 3, 7, 8]
idx ==> [0, 0, 1, 2, 2, 2, 3, 4, 4]
The function tf.unique(x, name=None) finds the unique elements in a 1-D tensor. And it now returns two value: y and idx. y contains all of the unique elements of x sorted inthe same order that they occur in x. idx contains the index of each value of x in the unique output y.
How I wish it has a third return value which contains the first index of each value of y in the original tensor x is also needed. It might work like this:
# tensor 'x' is [1, 1, 2, 3, 3, 3, 7, 8, 8]
y, idx, idx_ori = tf.unique(x)
y ==> [1, 2, 3, 7, 8]
idx ==> [0, 0, 1, 2, 2, 2, 3, 4, 4]
idx_ori ==> [0, 2, 3, 6, 7]
Just like its equivalent in Numpy does:
array 'x' is [1, 1, 2, 3, 3, 3, 7, 8, 8]
y, idx_ori = np.unique(x, return_index=True)
y ==> [1, 2, 3, 7, 8]
idx_ori ==> [0, 2, 3, 6, 7]
IF i have this idx_ori, i can solve my problem by tf.gather():
_, _1, idx_ori = tf.unique(a[:, 0])
result = tf.gather(a, idx_ori)
Any idea to workaround this problem? or any idea to get this indices that i want.
P.S. I know my description is tediously long ... :-p
This is a bit gross, but you could do:
print a
y, idx = tf.unique(a[:,0])
z = tf.one_hot(idx, tf.shape(y)[0])
s = tf.cumsum(z)
e = tf.equal(s, 1) # only seen once so far
ss = tf.to_int32(e) * tf.to_int32(z) # and we equal the thing
m = tf.reduce_max(ss, reduction_indices=1)
out = tf.boolean_mask(a, tf.equal(m, 1))
sess = tf.Session()
print sess.run(out)
[[1 2 3]
[2 2 3]
[2 2 4]
[3 2 3]
[4 2 3]]
[[1 2 3]
[2 2 3]
[3 2 3]
[4 2 3]]

Categories

Resources