The corresponding ctypes type of a numpy.dtype? - numpy

If I have a numpy ndarray with a certain dtype, how do I know what is the corresponding ctypes type?
For example, if I have a ndarray, I can do the following to convert it to a shared array:
import multiprocessing as mp
import numpy as np
import ctypes
x_np = np.random.rand(10, 10)
x_mp = mp.Array(ctypes.c_double, x_np)
However, I have to specify c_double here. It works if I don't specify the exact same type, but I would like to keep the type the same. How should I find out the ctypes type of the ndarray x_np automatically, at least for some common elementary data types?

This is now supported by numpy.ctypeslib.as_ctypes_type(dtype):
import numpy as np
x_np = np.random.rand(10, 10)
np.ctypeslib.as_ctypes_type(x_np.dtype)
Gives ctypes.c_double, as expected.

There is actually a way to do this that's built into Numpy:
x_np = np.random.rand(10, 10)
typecodes = np.ctypeslib._get_typecodes()
typecodes[x_np.__array_interface__['typestr']]
Output:
ctypes.c_double
The caveat is that the np.ctypeslib._get_typecodes function is marked as private (ie it's name starts with _). However, it doesn't seem like its implementation has changed in some time, so you can probably use it fairly reliably.
Alternatively, the implementation of _get_typecodes is pretty short, so you could just also copy the whole function over to your own code:
import ctypes
import numpy as np
def get_typecodes():
ct = ctypes
simple_types = [
ct.c_byte, ct.c_short, ct.c_int, ct.c_long, ct.c_longlong,
ct.c_ubyte, ct.c_ushort, ct.c_uint, ct.c_ulong, ct.c_ulonglong,
ct.c_float, ct.c_double,
]
return {np.dtype(ctype).str: ctype for ctype in simple_types}

Related

System of second order ode

I am trying to solve an IVP, consisting of two second order ode. I use sympy. No problems to obtain general solution. But I don't understand how to plug in the IC:s.
MWE:
from sympy import *
import numpy as np
import matplotlib.pyplot as plt
x1,x2=symbols('x1,x2',cls=Function)
t,k1,k2,m1,m2=symbols('t k1 k2 m1 m2',real=True)
k1=1.0
k2=1.0
m1=1.0
m2=1.0
eq1=Eq(m1*diff(x1(t),t,2)+k1*x1(t)-k2*(x2(t)-x1(t)),0)
eq2=Eq(m2*diff(x2(t),t,2)+k2*(x2(t)-x1(t)),0)
eqs=[eq1,eq2]
IC1={x1(0):0,x1(t).diff().subs(t,0):0}
IC2={x2(0):1,x2(t).diff().subs(t,0):0}
sol=dsolve(eqs,[x1(t),x2(t)],ics=[IC1,IC2])
print(sol)
Error message:
for funcarg, value in ics.items():
AttributeError: 'list' object has no attribute 'items'

Rolling multidimensional function in pandas

Let's say, I have the following code.
import numpy as np
import pandas as pd
x = pd.DataFrame(np.random.randn(100, 3)).rolling(window=10, center=True).cov()
For each index, I have a 3x3 matrix. I would like to calculate eigenvalues and then some function of those eigenvalues. Or, perhaps, I might want to compute some function of eigenvalues and eigenvectors. The point is that if I take x.loc[0] then I have no problem to compute anything from that matrix. How do I do it in a rolling fashion for all matrices?
Thanks!
You can use the analogous eigenvector/eigenvalue methods in spicy.sparse.linalg.
import numpy as np
import pandas as pd
from scipy import linalg as LA
x = pd.DataFrame(np.random.randn(100, 3)).rolling(window=10, center=True).cov()
for i in range(len(x)):
try:
e_vals,e_vec = LA.eig(x.loc[i])
print(e_vals,e_vec)
except:
continue
If there are no NaN values present then you need not use the try and except instead go for only for loop.

Plot Scipy ODE solution

I've been trying to solve a nonlinear ordinary differential equation numerically by using Scipy, in particular by the scipy.integrate.RK23 command. It returns <scipy.integrate._ivp.rk.RK23 at 0x7f2b1a908390>. How can I plot the solution?
Thank you in advance for your help!
EDIT:
As a simple example for testing:
import numpy
import scipy.integrate
t0=0;
tf=1;
x0=numpy.array([0]);
def F(t,x): return t**2;
x=scipy.integrate.RK23(F,t0,x0,tf)
RK23 is a class that implements a way to solve an ODE, that is, it is an OdeSolver so it should not be used directly but in other functions like solve_ivp:
import numpy
from scipy.integrate import solve_ivp, RK23
import matplotlib.pyplot as plt
t0=0
tf=1
x0=numpy.array([0])
def F(t,x): return t**2
sol = solve_ivp(F, [t0, tf], x0, RK23)
print(sol)
plt.plot(sol.t, sol.y[0])
plt.show()
OdeSolver allows the developer to add custom methods without the need to rewrite scipy, but since RK23 is a classic method already implemented by scipy, you could pass just the name and scipy search for the appropriate class:
...
sol = solve_ivp(F, [t0, tf], x0, "RK23")
...

Change data type in Numpy and Nibabel

I'm trying to convert numpy arrays into Nifti file format using Nibabel. Some of my Numpy arrays have dtype('<i8') when it should be dtype('uint8') when Nibabel calls for the data type.
arr.get_data_dtype()
Does anyone know how to convert and save Numpy arrays' data type?
The question of the title is slightly different than the question in the text. So...
If you want to change the data-type of a numpy array arr to np.int8, you are looking for arr.astype(np.int8).
Mind that you may lose precision due to data casting (see astype documentation)
To save it afterwards you may want to see ?np.save and ?np.savetxt (or to check the library pickle, to save more general objects than numpy array).
If you want to change the data-type of a nifti image saved in my_image.nii.gz
you have to go for:
import nibabel as nib
import numpy as np
image = nib.load('my_image.nii.gz')
# to be extra sure of not overwriting data:
new_data = np.copy(image.get_data())
hd = image.header
# in case you want to remove nan:
new_data = np.nan_to_num(new_data)
# update data type:
new_dtype = np.int8 # for example to cast to int8.
new_data = new_data.astype(new_dtype)
image.set_data_dtype(new_dtype)
# if nifty1
if hd['sizeof_hdr'] == 348:
new_image = nib.Nifti1Image(new_data, image.affine, header=hd)
# if nifty2
elif hd['sizeof_hdr'] == 540:
new_image = nib.Nifti2Image(new_data, image.affine, header=hd)
else:
raise IOError('Input image header problem')
nib.save(new_image, 'my_image_new_datatype.nii.gz')
Finally if you have a numpy array my_arr and you want to save it into a nifti image with a given data-type np.my_dtype, you can do:
import nibabel as nib
import numpy as np
new_image = nib.Nifti1Image(my_arr, np.eye(4))
new_image.set_data_dtype(np.my_dtype)
nib.save(new_image, 'my_arr.nii.gz')
Hope it helps!
NOTE: If you are using ITKsnap you may want to use np.float32, np.float64, np.uint16, np.uint8, np.int16, np.int8. Other choices may not produce images that can be open with this software.
Seems like you could also do
import nibabel
img = nibabel.load(filename)
img.set_data_dtype(dtype)
img.to_filename(new_filename)
You can use nilearn for a tidy solution. Here is an example if you want to change the data type of nifti image to int16:
from nilearn import image
import numpy as np
vol = image.load_img(input_file)
vol = image.new_img_like(vol, np.int16(vol.get_fdata()))
vol.to_filename(output_file)
Datatypes for .nii files can also be specified in the .to_filename() function:
import nibabel as nib
new_image = nib.Nifti2Image(my_arr, affine)
new_image.to_filename(fn, dtype=np.uint8)

Dtype work in FROM but not IMPORT

I swear I read almost all the "FROM vs IMPORT" questions before asking this.
While going through the NumPy tutorial I was using:
import numpy as np
but ran into trouble when declaring dtype of a matrix like:
a = np.ones((2,3),dtype=int32)
I kept getting "NameError: name 'int32' is not defined." I am using Python v3.2, and am following the tentative tutorial that goes along with it. I used:
from numpy import *
a = ones((2,3),dtype=int32)
Which works. Any insight as to why this is would be much appreciated.
Thank you in advance!
import numpy as np
#this will work because int32 is defined inside the numpy module
a = np.ones((2,3), dtype=np.int32)
#this also works
b = np.ones((2,3), dtype = 'int32')
#python doesn't know what int32 is because you loaded numpy as np
c = np.ones((2,3), dtype=int32)
back to your example:
from numpy import *
#this will now work because python knows what int32 is because it is loaded with numpy.
d = np.ones((2,3), dtype=int32)
I tend to define the type using strings as in array b