8

Very simple question: I have a structured array with multiple columns and I'd like to fill only some of them (but more than one) with another preexisting array.

This is what I'm trying:

strc = np.zeros(4, dtype=[('x', int), ('y', int), ('z', int)])
x = np.array([2, 3])
strc[['x', 'y']][0] = x

This gives me this future warning:

main:1: FutureWarning: Numpy has detected that you (may be) writing to an array returned by numpy.diagonal or by selecting multiple fields in a record array. This code will likely break in a future numpy release -- see numpy.diagonal or arrays.indexing reference docs for details. The quick fix is to make an explicit copy (e.g., do arr.diagonal().copy() or arr[['f0','f1']].copy()).

But even though this is a warning, the structured array doesn't get filled. So far I'm iterating over both arrays and it works but I guess that's highly inefficient. Is there a better way?

1
  • stackoverflow.com/questions/3058602/… points out that trying to index several fields produces a copy, not a view. If you are working with more rows than fields, there's nothing wrong with iterating over fields. Commented Feb 17, 2014 at 5:59

2 Answers 2

12

If all the field have the same dtype, you can create a view:

import numpy as np
strc = np.zeros(4, dtype=[('x', int), ('y', int), ('z', int)])
strc_view = strc.view(int).reshape(len(strc), -1)
x = np.array([2, 3])
strc_view[0, [0, 1]] = x

If you want a common solution that can create columns views of any structured array, you can try:

import numpy as np
strc = np.zeros(3, dtype=[('x', int), ('y', float), ('z', int), ('t', "i8")])

def fields_view(arr, fields):
    dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
    return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)

v1 = fields_view(strc, ["x", "z"])
v1[0] = 10, 100

v2 = fields_view(strc, ["y", "z"])
v2[1:] = [(3.14, 7)]

v3 = fields_view(strc, ["x", "t"])

v3[1:] = [(1000, 2**16)]

print strc

here is the output:

[(10, 0.0, 100, 0L) (1000, 3.14, 7, 65536L) (1000, 3.14, 7, 65536L)]
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you HYRY, I think your solution is too much for my little unefficiency uneasyness but it may be useful for someone else
0

Your example gives now (numpy v1.18.5) the error ValueError: setting an array element with a sequence.. But it will work with

strc[['x', 'y']][0] = tuple(x)

Another example

A = np.zeros(4, dtype=[('x', int), ('y', float), ('z', 'U3')])

A[['x', 'z']][0] = 44, 'foo'

print(*A, sep="\n")
# (44, 0., 'foo')
# (0, 0., '')
# (0, 0., '')
# (0, 0., '')

Note also that when first indexing the row A[0][['x', 'z']] = 44, 'foo', this will raise IndexError: invalid index; but A[0:1][['x', 'z']] = 44, 'foo' will work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.