'How do I convert an array of numpy booleans to python booleans for serialization (e.g. for mongodb)?

I have a numpy array of booleans:

import numpy as np
x = np.zeros(100).astype(np.bool)
x[20] = True # say

When I try to insert this (one element per document) as part of an OrderedDict into mongodb, I get the following error:

InvalidDocument: cannot encode object: False, of type: <class 'numpy.bool_'>

This is a serialization issue I have encountered before for singleton numpy booleans.

How do I convert the numpy array into an array of python booleans for serialization?

The following did not work:

y = x.astype(bool)


Solution 1:[1]

So, I have just this week come across a solution to this (albeit my own) question from two years ago... Thanks SO!

I am going to invoke the brilliant numpyencoder (https://pypi.org/project/numpyencoder) as follows:

# Set up the problem
import numpy as np
x = np.zeros(100).astype(bool) # Note: bool <- np.bool is now deprecated!
x[20] = True

# Let's roll
import json
from numpyencoder import NumpyEncoder
sanitized_json_string = json.dumps(x, cls=NumpyEncoder)

# One could stop there since the payload is now ready to go - but just to confirm:

x_sanitized=json.loads(sanitized_json_string)
print(x_sanitized)

Solution 2:[2]

You can use numpy.ndarray.tolist here.

import numpy as np
x = np.zeros(100).astype(np.bool)
y = x.tolist()

print(type(x))
# numpy.ndarray
print(type(x[0]))
# numpy.bool_

print(type(y))
# list
print(type(y[0]))
# bool

Solution 3:[3]

You can try numpy.asscalar

import numpy as np
x = np.zeros(100).astype(np.bool)
z = [np.asscalar(x_i) for x_i in x]
print(type(z))

You can also use item() which is a better option since asscalar is depreceted.

import numpy as np
x = np.zeros(100).astype(np.bool)
z = [x_i.item() for x_i in x]
print(type(z))
print(z)

For a longer list, tolist() is better option.

import numpy as np
import time
x = np.zeros(100000).astype(np.bool)
t1 = time.time()
z = [x_i.item() for x_i in x]
t2 = time.time()

print(t2-t1)
t1 = time.time()
z = x.tolist()
t2 = time.time()
print(t2-t1)
0.0519254207611084
0.0015206336975097656

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jtlz2
Solution 2
Solution 3