Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Numpy structure scalar instead of array

Tags:

python

numpy

I just discovered Numpy structured arrays and I find them to be quite powerful. The natural question arises in my mind: How in the world do I create a Numpy structure scalar. Let me show you what I mean. Let's say I want a structure containing some data:

import numpy as np
dtype = np.dtype([('a', np.float_), ('b', np.int_)])
ar = np.array((0.5, 1), dtype=dtype)
ar['a']

This gives me array(0.5) instead of 0.5. On the other hand, if I do this:

import numpy as np
dtype = np.dtype([('a', np.float_), ('b', np.int_)])
ar = np.array([(0.5, 1)], dtype=dtype)
ar[0]['a']

I get 0.5, just like I want. Which means that ar[0] isn't an array, but a scalar. Is it possible to create a structured scalar in a way more elegant than the one I've described?

like image 550
Hameer Abbasi Avatar asked Dec 11 '17 15:12

Hameer Abbasi


1 Answers

Singleton isn't quite the right term, but I get what you want.

arr = np.array((0.5, 1), dtype=dtype)

Creates a 0d, single element array of this dtype. Check its dtype and shape.

arr.item() returns a tuple (0.5, 1). Aso test arr[()] and arr.tolist().

np.float64(0.5) creates a float with a numpy wrapper. It is similar to, but exactly the same as np.array(0.5). Their methods diff some.

I don't know anything similar with a compound dtype.


In [123]: dt = np.dtype('i,f,U10')
In [124]: dt
Out[124]: dtype([('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [125]: arr = np.array((1,2,3),dtype=dt)
In [126]: arr
Out[126]: 
array((1,  2., '3'),
      dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [127]: arr.shape
Out[127]: ()

arr is a 0d 1 element array. It can be indexed with:

In [128]: arr[()]
Out[128]: (1,  2., '3')
In [129]: type(_)
Out[129]: numpy.void

This indexing produces a np.void object. Doing the same thing on a 0d float array would produce a np.float object.

But you can't use np.void((1,2,3), dtype=dt) to directly create such an object (in contrast to np.float(12.34)).

item is the normal way of extracting a 'scalar' from an array. Here it returns a tuple, the same sort of object that we used as input to create arr:

In [131]: arr.item()
Out[131]: (1, 2.0, '3')
In [132]: type(_)
Out[132]: tuple

np.asscalar(arr) returns the same tuple.

One difference between the np.void object and the tuple, is that it can still be indexed with the field name, arr[()]['f0'], whereas the tuple has to be indexed by number arr.item()[0]. The void still has a dtype, while the tuple doesn't.

fromrecords makes a recarray. This is similar to a structured array, but allows us to access fields as attributes. It may actually be an older class, that has been merged to into numpy, hence the np.rec prefix. Mostly we use structured arrays, though np.rec still has some convenience functions. (actually in numpy.lib.recfunctions):

In [133]: res = np.rec.fromrecords((1,2,3), dt)
In [134]: res
Out[134]: 
rec.array((1,  2., '3'), 
          dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [135]: res.f0
Out[135]: array(1, dtype=int32)
In [136]: res.item()
Out[136]: (1, 2.0, '3')
In [137]: type(_)
Out[137]: tuple
In [138]: res[()]
Out[138]: (1, 2.0, '3')
In [139]: type(_)
Out[139]: numpy.record

So this produced a np.record instead of a np.void. But that's just a subclass:

In [143]: numpy.record.__mro__
Out[143]: (numpy.record, numpy.void, numpy.flexible, numpy.generic, object)

Accessing a structured array by field name gives an array of the corresponding dtype (and same shape)

In [145]: arr['f1']
Out[145]: array(2.0, dtype=float32)
In [146]: arr[()]['f1']
Out[146]: 2.0
In [147]: type(_)
Out[147]: numpy.float32

Out[146] could also be created with np.float32(2.0).


Checking my comment on the ar[0] for the 1d array:

In [158]: arr1d = np.array([(1,2,3)], dt)
In [159]: arr1d
Out[159]: 
array([(1,  2., '3')],
      dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [160]: arr1d[0]
Out[160]: (1,  2., '3')
In [161]: type(_)
Out[161]: numpy.void

So arr[()] and arr1d[0] do the same thing for their respective sized arrays. Likewise arr2d[0,0], which can also be written as arr2d[(0,0)].

like image 183
hpaulj Avatar answered Sep 20 '22 05:09

hpaulj