If your Kernel class has a predictable amount of member data, then you could define a dtype for it instead of a class. e.g. if it's parameterized by 9 floats and an int, you could do

kerneldt = np.dtype([('myintname', np.int32), ('myfloats', np.float64, 9)])
arr = np.empty(dims, dtype=kerneldt)

You'll have to do some coercion to turn them into objects of class Kernel every time you want to manipulate methods of a single kernel but that's one way to store the actual data in a NumPy array. If you want to only store a reference, then the object dtype is the best you can do without subclassing ndarray.

Answer from dwf on Stack Overflow
🌐
NumPy
numpy.org › doc › stable › reference › arrays.dtypes.html
Data type objects (dtype) — NumPy v2.5 Manual
In NumPy 1.7 and later, this form allows base_dtype to be interpreted as a structured dtype. Arrays created with this dtype will have underlying dtype base_dtype but will have fields and flags taken from new_dtype. This is useful for creating custom structured dtypes, as done in record arrays.
🌐
GeeksforGeeks
geeksforgeeks.org › python › numpy-data-type-objects
NumPy - Data type Objects(dtype) - GeeksforGeeks
July 23, 2025 - import numpy as np # Integer data type x = np.array([1, 2, 3], dtype='int32') print(x.dtype) # Float data type y = np.array([1.1, 2.2, 3.3], dtype='float64') print(y.dtype) ... We can define a custom dtype using the numpy.dtype constructor.
🌐
Python Course
python-course.eu › numerical-programming › numpy-data-objects-dtype.php
3. Numpy Data Objects, dtype | Numerical Programming
This makes it possible to define and manage complex data like the one in the following table using a custom dtype: Before we work with a complex data structure like the one shown above, let’s first introduce dtype using a very simple example. We define a data type based on int16 and refer to it as i16. (Admittedly, this isn’t a very descriptive name, but we’ll use it just for this example.) The elements of a list named lst are then converted to the i16 type to create a two-dimensional array called A. import numpy as np i16 = np.dtype(np.int16) print(i16) lst = [ [3.4, 8.7, 9.9], [1.1, -7.8, -0.7], [4.1, 12.3, 4.8] ] A = np.array(lst, dtype=i16) print(A)
Author: WarrenWeckesser
🌐
Statology
statology.org › home › how to create a custom numpy dtype for specialized data handling
How to Create a Custom NumPy Dtype for Specialized Data Handling How to Create a Custom NumPy Dtype for Specialized Data Handling
April 22, 2025 - Sometimes, a structured dtype is not sufficient, and you need full control over how data is stored and represented. For this, NumPy provides a way to define custom dtypes using np.dtype and user-defined data representations.
🌐
Boostorg
boostorg.github.io › python › doc › html › numpy › tutorial › dtype.html
How to use dtypes - Boost.Python NumPy extension 1.0 documentation
std::cout << "Datatype is:\n" << p::extract<char const *>(p::str(a.get_dtype())) << std::endl ; We can also create custom dtypes and build ndarrays with the custom dtypes
🌐
NumPy
numpy.org › devdocs › reference › arrays.dtypes.html
Data type objects (dtype) — NumPy v2.6.dev0 Manual
In NumPy 1.7 and later, this form allows base_dtype to be interpreted as a structured dtype. Arrays created with this dtype will have underlying dtype base_dtype but will have fields and flags taken from new_dtype. This is useful for creating custom structured dtypes, as done in record arrays.
Top answer
1 of 2
3

All 3 requirements conflict with a view.

Ignoring the header field requires selecting the other fields. Selecting a single field is clearly a view, but the state of multiple fields is in flux. When I try anything besides simply viewing the values I get a warning:

In [497]: dt=np.dtype('U10,f,f,f,f')
In [498]: x=np.zeros((5,),dt)

In [505]: x[['f1','f3']].__array_interface__
/usr/bin/ipython3: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()).

Remember, the data is layed out element by element, with the dtype tuple values in compact blocks - essentially a compact version of the display. Ignoring the header requires skipping that set of bytes. view can handle skips produced by strides, but not these dtype field skips.

In [533]: x
Out[533]: 
array([('header', 0.0, 5.0, 1.0, 10.0), ('header', 1.0, 4.0, 1.0, 10.0),
       ('header', 2.0, 3.0, 1.0, 10.0), ('header', 3.0, 2.0, 1.0, 10.0),
       ('header', 4.0, 1.0, 1.0, 10.0)], 
      dtype=[('f0', '<U10'), ('f1', '<f4'), ('f2', '<f4'), ('f3', '<f4'), ('f4', '<f4')])

To explore reordering the complex fields, lets try a 2d array:

In [509]: y=np.arange(10.).reshape(5,2)  # 2 column float
In [510]: y.view(complex)    # can be viewed as complex
Out[510]: 
array([[ 0.+1.j],
       [ 2.+3.j],
       [ 4.+5.j],
       [ 6.+7.j],
       [ 8.+9.j]])
In [511]: y[:,::-1].view(complex)
...
ValueError: new type not compatible with array.

To switch the real/imaginay columns I have to make a copy. complex requires that the 2 floats be contiguous and in order.

In [512]: y[:,::-1].copy().view(complex)
Out[512]: 
array([[ 1.+0.j],
       [ 3.+2.j],
       [ 5.+4.j],
       [ 7.+6.j],
       [ 9.+8.j]])

float32 to float64 is clearly not a view change. One uses 4 bytes per number, the other 8. You can't 'view' 4 as 8 without copying.

2 of 2
2

@hpaulj is absolutely correct that this conflicts with a view.

However, you may be asking the wrong question.

numpy can certainly do what you're wanting to do but you'll need to make a temporary copy in memory.

Overall, you're probably better served by rethinking the "read the entire file into memory and then view it" approach. Instead seek past (or read in) the header, then read in the data portion with fromfile. After than, it's relatively straightforward to manipulate things into what you want, as long as you don't mind making a copy to go from float32's to float64's.


To start out with, let's generate a file similar to yours:

import numpy as np

reals = np.arange(100).astype(np.float32)
imag = -9999.0 * np.ones(100).astype(np.float32)

data = np.empty(reals.size + imag.size, dtype=np.float32)
data[::2], data[1::2] = imag, reals

with open('temp.dat', 'wb') as outfile:
    # Write a 1Kb header (of literal "x"'s, in this case)
    outfile.write(1024 * 'x')
    outfile.write(data)

Now we'll read it in.

The key to ignoring the header is to seek past it before reading the data in with fromfile.

Then, we can de-interleave the data and convert to 64-bit floats at the same time.

Finally, you can then view the resulting 2xN-length float64 array as an N-length complex128 array. (Note: complex128 is the 64-bit version of a complex number. complex64 is the 32-bit version.)

For example:

import numpy as np

with open('temp.dat', 'rb') as infile:
    # Seek past header
    infile.seek(1024)

    # Read in rest of file as float32's
    data = np.fromfile(infile, dtype=np.float32)

result = np.empty(data.size, np.float64)

# De-interleave imag & real back into expected real & imag, converting to 64-bit
result[::2], result[1::2] = data[1::2], data[::2]

# View the result as complex128's (i.e. 64-bit complex numbers)
result = result.view(np.complex128)
Find elsewhere
🌐
Data Science Dojo
discuss.datasciencedojo.com › python
How to make custom dtype in NumPy array? - Python - Data Science Dojo Discussions
February 22, 2023 - I’m working on a data science project in which right now my main task is to create custom datatypes with specific bytes of memory. I used NumPy for it and developed a code that is below: I want to know if any other al…
🌐
Quansight
quansight.com › home › post › my numpy year: creating a dtype for the next generation of scientific computing
My NumPy Year: Creating a DType for the Next Generation of Scientific Computing | Quansight Consulting
October 30, 2024 - As a side note, the NumPy 2.0 DType API makes it much easier to support different kinds of data. If you’ve ever felt like NumPy needed better support for custom data types and found it difficult, it’s now easier than it used to be. It’s also possible to write more complicated DTypes, like physical units, arbitrary-precision floats, or categorical DTypes.
🌐
www.droidbiz.in
droidbiz.in › numpy › numpy-custom-data-types-and-user-defined-functions
NumPy Custom Data Types and User-defined Functions
The simplest way to create NumPy custom data types is by passing a list of tuples to the numpy.dtype constructor.
🌐
GitHub
github.com › numpy › numpy › wiki › Dtype-Brainstorming
Dtype Brainstorming · numpy/numpy Wiki · GitHub
October 22, 2018 - Ideally, custom dtypes would reuse existing protocols for duck arrays, e.g., __array_ufunc__ and __array_function__. Mechanism for extended dtypes to go from strings to dtypes · Parse dtype='my_dtype[options]' into the dtype constructor somehow. ... Should not require every .dtype attribute to be a NumPy dtype (e.g., pandas_series.dtype == np.dtype(np.float64) current breaks)
Author: numpy
🌐
NumPy
numpy.org › devdocs › reference › c-api › dtype.html
Data type API — NumPy v2.6.dev0 Manual
Before NumPy 2.0, this was the same as Py_intptr_t. While a better match, this did not match actual usage in practice. On the Python side, we still support np.dtype('p') to fetch a dtype compatible with storing pointers, while n is the correct character for the ssize_t.
🌐
Boost
beta.boost.org › doc › libs › 1_68_0 › libs › python › doc › html › numpy › reference › dtype.html
dtype - Boost.Python NumPy extension 1.0 documentation - 1.68.0
namespace p = boost::python; namespace np = boost::python::numpy; np::dtype dtype = np::dtype::get_builtin<double>(); p::tuple for_custom_dtype = p::make_tuple("ha",dtype); np::dtype custom_dtype = np::dtype(list_for_dtype);
🌐
Sling Academy
slingacademy.com › article › create-use-custom-numpy-dtypes
How to Create and Use Custom NumPy dtypes - Sling Academy
Or maybe you need to align with ... dtypes that suit your particular needs. Structured dtypes in NumPy allow you to define arrays with multiple fields, each potentially of a different dtype....
🌐
Spark Code Hub
sparkcodehub.com › numpy › advanced › custom dtypes
Mastering Custom Dtypes in NumPy: Unlocking Flexible ...
Custom dtypes enable you to define structured arrays or record arrays, where each element is a composite of multiple fields, akin to a database record or C struct. We’ll cover the mechanics, provide practical examples, and address common questions ...
Top answer
1 of 2
2

Numpy arrays are most suitable for data types with fixed size. If the objects in the array are not fixed size (such as your MultiEvent) the operations can become much slower.

I would recommend you to store all of the survival times in a 1d linear record array with 3 fields: event_id, time, period. Each event can appear mutliple times in the array:

>>> import numpy as np
>>> rawdata = [(1, 0.4, 4), (1, 0.6, 6), (2,2.6, 6)]
>>> npdata = np.rec.fromrecords(rawdata, names='event_id,time,period')
>>> print npdata
[(1, 0.40000000000000002, 4) (1, 0.59999999999999998, 6) (2, 2.6000000000000001, 6)]

To get data for a specific index you could use fancy indexing:

>>> eventdata = npdata[npdata.event_id==1]
>>> print eventdata
[(1, 0.40000000000000002, 4) (1, 0.59999999999999998, 6)]

The advantage of this approach is that you can easily intergrate it with your ndarray-based functions. You can also access this arrays from cython as described in the manual:

cdef packed struct Event:
    np.int32_t event_id
    np.float64_t time
    np.float64_6 period

def f():
    cdef np.ndarray[Event] b = np.zeros(10,
        dtype=np.dtype([('event_id', np.int32),
                        ('time', np.float64),
                        ('period', np.float64)]))
    <...>
2 of 2
0

I apologise for not answering the question directly, but I've had similar problems before, and if I understand correctly, the real problem you're now having is that you have variable-length data, which is really, really not one of the strengths of numpy, and is the reason you're running into performance issues. Unless you know in advance the maximum number of entries for a multievent, you'll have problems, and even then you'll be wasting loads of memory/disk space filled with zeros for those events that aren't multi events.

You have data points with more than one field, some of which are related to other fields, and some of which need to be identified in groups. This hints strongly that you should consider a database of some form for storing this information, for performance, memory, space-on-disk and sanity reasons.

It will be much easier for a person new to your code to understand a simple database schema than a complicated, hacked-on-numpy structure that will be frustratingly slow and bloated. SQL queries are quick and easy to write in comparison.

I would suggest based on my understanding of your explanation having Event and MultiEvent tables, where each Event entry has a foreign key into the MultiEvent table where relevant.

🌐
W3Schools
w3schools.com › python › numpy › numpy_data_types.asp
NumPy Data Types
We use the array() function to create arrays, this function can take an optional argument: dtype that allows us to define the expected data type of the array elements: ... import numpy as np arr = np.array([1, 2, 3, 4], dtype='S') print(arr) ...
🌐
GitHub
github.com › pybind › pybind11 › issues › 2259
numpy: Request for user-defined types? (beyond structured dtypes and dtype=object) · Issue #2259 · pybind/pybind11
June 21, 2020 - I realized that I didn't create an upstream issue, so I'm placing this here. Background for NumPy Basically, NumPy can allow to do custom dtypes through 3 different mechanisms (that I'm aware of): Structured Types (pybind11 documentation...
Author: pybind