Reputation: 321
is it possible to store references of specific rows of an numpy array in another numpy array?
I have an array of 2D nodes, e.g.
nodes = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
Now I want to select only a few of them and store a reference in another numpy array:
nn = np.array([nodes[0], nodes[3]])
If I modify a entry in nn
the array nodes
remains unchanged. Is there a way to store a reference to nodes
in the ndarray nn
?
Upvotes: 2
Views: 1467
Reputation: 114330
You can store an index to the rows you want in a numpy array:
ref = np.array([0, 3])
You can use the reference in an indexing expression to access the nodes you want:
>>> nn = nodes[ref]
>>> nn
array([[1, 2],
[4, 5]])
nn
will be a deep copy with no connection to the original in this case. While nn[foo] = bar
won't affect the original array, you can use ref
directly:
>>> nodes[ref, 1] = [17, 18]
>>> nodes
array([[ 1, 17],
[ 2, 3],
[ 3, 4],
[ 4, 18],
[ 5, 6]])
Alternatively, you can use a mask for ref
:
>>> ref2 = np.zeros(nodes.shape[0], dtype=np.bool)
>>> ref2[ref] = True
>>> ref2
array([ True, False, False, True, False], dtype=bool)
You can do almost all the same operations:
>>> nn2 = nodes[ref2]
>>> nn2
array([[1, 2],
[4, 5]])
Modifications work too:
>>> nodes[ref2, 1] = [19, 23]
>>> nodes
array([[ 1, 19],
[ 2, 3],
[ 3, 4],
[ 4, 23],
[ 5, 6]])
The only thing that is more convenient with an array of indices is selecting a particular node from within the selection:
>>> nodes[ref[0], 0]
1
Upvotes: 1
Reputation: 7994
Method 1
First, initialize a Numpy array of None with dtype=object. (It don't have to be None. My guess it that you just cannot put references at initialization as Numpy somehow just creates an deep copy of it.)
Then, put the reference into the array.
nodes = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
# nn = np.array([nodes[0], nodes[1]],dtype=object) would not work
nn = np.array([None, None], dtype=object)
nn[0] = nodes[0]
nn[1] = nodes[3]
# Now do some modification.
nn[0][1] = 100
Output of nodes:
array([[ 1, 100],
[ 2, 3],
[ 3, 4],
[ 4, 5],
[ 5, 6]])
# make it a function
def make_ref(old_array, indeces):
ret = np.array([None for _ in range(len(indeces))])
for i in range(len(indeces)):
ret[i] = old_array[indeces[i]]
return ret
nn = make_ref(nodes, [0, 3])
Method 2
If you don't need to put it in Numpy arrays, just use a list to host the references.
nn = [nodes[0], nodes[1]]
Upvotes: 0
Reputation: 1314
In Numpy, you can get a view of an array that can be edited. In your example, you can do this:
import numpy as np
nodes = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
node_idx = np.array([0, 3])
nodes[node_idx] = np.array([[1, 5], [2, 5]])
nodes
Output:
array([[1, 5],
[2, 3],
[3, 4],
[2, 5],
[5, 6]])
You can also replace it with boolean arrays:
import numpy as np
nodes = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
node_mask = np.array([True, False, False, True, False])
nodes[node_mask] = np.array([[1, 5], [2, 5]])
nodes
Which produces the same result. Of course, this means you can do magic like this:
import numpy as np
nodes = np.array([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]])
nodes[nodes[:, 0] == 3] = [1, 5]
nodes
Which replaces all rows with the first element equal to 3
with [1, 5]
. Output:
array([[1, 2],
[2, 3],
[1, 5],
[4, 5],
[5, 6]])
Upvotes: 0
Reputation: 78554
If the reference can be created with basic indexing/slicing, then you get a view (an array that does not own its data, but refers to another array’s data instead) of the initial array where changes propagate:
>>> nn = nodes[0:4:3] # reference array for rows 0 and 3
>>> nn[0][0] = 0
>>> nodes
array([[0, 2],
[2, 3],
[3, 4],
[4, 5],
[5, 6]])
Otherwise, you get a copy from the original array as in your code, and updates do not propagate to the initial array.
Upvotes: 2