Массив NumPy не поддерживает сериализацию в формате JSON

107

После создания массива NumPy и сохранения его как переменной контекста Django, я получаю следующую ошибку при загрузке веб-страницы:

array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) is not JSON serializable

Что это значит?

  • 16
    Это означает, что где-то что-то пытается сбросить массив с помощью модуля json . Но numpy.ndarray - это не тот тип, с которым json знает, как обращаться. Вам нужно будет либо написать свой собственный сериализатор, либо (проще) передать list(your_array) тому, что пишет json.
  • 13
    list(your_array) не всегда будет работать, так как он возвращает целые числа, а не нативные. your_array.to_list() этого используйте your_array.to_list() .
Показать ещё 1 комментарий
Теги:
numpy

13 ответов

143
Лучший ответ

Я регулярно "jsonify" np.arrays. Сначала попробуйте использовать метод ".tolist()" на массивах, например:

import numpy as np
import codecs, json 

a = np.arange(10).reshape(2,5) # a 2 by 5 array
b = a.tolist() # nested lists with same data, indices
file_path = "/path.json" ## your path variable
json.dump(b, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4) ### this saves the array in .json format

Чтобы "unjsonify" использовать массив:

obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)
  • 1
    Почему его можно хранить только в виде списка списков?
  • 0
    Я не знаю, но я ожидаю, что у типов np.array есть метаданные, которые не вписываются в json (например, они указывают тип данных каждой записи как float)
Показать ещё 6 комментариев
81
class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

a = np.array([1, 2, 3])

print (json.dumps({'aa': [2, (2, 3, 4), a], 'bb': [2]}, ЦБС = NumpyEncoder))

{ "aa": [2, [2, 3, 4], [1, 2, 3]], "bb": [2]}

  • 11
    Это должно быть намного выше, это общий и правильно абстрагированный способ сделать это. Спасибо!
  • 1
    Есть ли простой способ вернуть ndarray из списка?
Показать ещё 3 комментария
29

Вы можете использовать Pandas:

import pandas as pd
pd.Series(your_array).to_json(orient='values')
  • 2
    Большой! И я думаю, что для 2D np.array это будет что-то вроде pd.DataFrame(your_array).to_json('data.json', orient='split') .
  • 0
    @yurenzhong: Какие данные? Может быть, вы должны оставить свой вопрос?
15

Я нашел лучшее решение, если у вас вложенные массивы numpy в словаре:

import json
import numpy as np

class NumpyEncoder(json.JSONEncoder):
    """ Special json encoder for numpy types """
    def default(self, obj):
        if isinstance(obj, (np.int_, np.intc, np.intp, np.int8,
            np.int16, np.int32, np.int64, np.uint8,
            np.uint16, np.uint32, np.uint64)):
            return int(obj)
        elif isinstance(obj, (np.float_, np.float16, np.float32, 
            np.float64)):
            return float(obj)
        elif isinstance(obj,(np.ndarray,)): #### This is the fix
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

dumped = json.dumps(data, cls=NumpyEncoder)

with open(path, 'w') as f:
    json.dump(dumped, f)

Спасибо этому парню.

  • 0
    Спасибо за полезный ответ! Я записал атрибуты в файл json, но теперь у меня возникают проблемы при чтении параметров логистической регрессии. Есть ли «декодер» для этого сохраненного файла JSON?
  • 0
    Конечно, чтобы прочитать json обратно, вы можете использовать это: with open(path, 'r') as f: data = json.load(f) , который возвращает словарь с вашими данными.
Показать ещё 1 комментарий
2

Это не поддерживается по умолчанию, но вы можете заставить его работать довольно легко! Есть несколько вещей, которые вы хотите закодировать, если хотите получить точные данные:

  • Сами данные, которые вы можете получить с помощью obj.tolist() в качестве упоминаемых @travelingbones. Иногда это может быть достаточно хорошим.
  • Тип данных. Я чувствую, что это важно в некоторых случаях.
  • Размер (не обязательно 2D), который может быть получен из вышеприведенного, если вы считаете, что вход действительно является "прямоугольной" сеткой.
  • Порядок памяти (строка или столбец). Это не часто имеет значение, но иногда это происходит (например, производительность), так почему бы не сохранить все?

Кроме того, ваш массив numpy может быть частью вашей структуры данных, например. у вас есть список с некоторыми матрицами внутри. Для этого вы можете использовать собственный кодировщик, который в основном делает это.

Этого должно быть достаточно для реализации решения. Или вы можете использовать json-tricks, который делает именно это (и поддерживает различные другие типы) (отказ от ответственности: я сделал это).

pip install json-tricks

Тогда

data = [
    arange(0, 10, 1, dtype=int).reshape((2, 5)),
    datetime(year=2017, month=1, day=19, hour=23, minute=00, second=00),
    1 + 2j,
    Decimal(42),
    Fraction(1, 3),
    MyTestCls(s='ub', dct={'7': 7}),  # see later
    set(range(7)),
]
# Encode with metadata to preserve types when decoding
print(dumps(data))
1

Вы также можете использовать аргумент по default например:

def myconverter(o):
    if isinstance(o, np.float32):
        return float(o)

json.dump(data, default=myconverter)
1

У меня была аналогичная проблема с вложенным словарем с некоторыми numpy.ndarrays в нем.

def jsonify(data):
    json_data = dict()
    for key, value in data.iteritems():
        if isinstance(value, list): # for lists
            value = [ jsonify(item) if isinstance(item, dict) else item for item in value ]
        if isinstance(value, dict): # for nested lists
            value = jsonify(value)
        if isinstance(key, int): # if key is integer: > to string
            key = str(key)
        if type(value).__module__=='numpy': # if value is numpy.*: > to python list
            value = value.tolist()
        json_data[key] = value
    return json_data
0

Ошибка типа: массив ([[0.46872085, 0.67374235, 1.0218339, 0.13210179, 0.5440686, 0.9140083, 0.58720225, 0.2199381]], dtype = float32) не поддерживает сериализацию JSON

Вышеупомянутая ошибка возникла, когда я попытался передать список данных в model.predict(), когда я ожидал ответа в формате json.

> 1        json_file = open('model.json','r')
> 2        loaded_model_json = json_file.read()
> 3        json_file.close()
> 4        loaded_model = model_from_json(loaded_model_json)
> 5        #load weights into new model
> 6        loaded_model.load_weights("model.h5")
> 7        loaded_model.compile(optimizer='adam', loss='mean_squared_error')
> 8        X =  [[874,12450,678,0.922500,0.113569]]
> 9        d = pd.DataFrame(X)
> 10       prediction = loaded_model.predict(d)
> 11       return jsonify(prediction)

Но, к счастью, нашла подсказку, чтобы разрешить возникшую ошибку. Сериализация объектов применима только для следующего преобразования. Отображение должно выполняться следующим образом: объект - dict массив - список строк - строка целое число - целое число

Если вы прокрутите вверх, чтобы увидеть строку с номером 10pretion =loaded_model.predict(d), где эта строка кода генерировала выходные данные типа массива данных типа, при попытке преобразовать массив в формат json это невозможно

Наконец, я нашел решение, просто преобразовав полученный вывод в список типов с помощью следующих строк кода

предсказание = загруженная_модель .predict(d)
listtype =вестиция .tolist() вернуть jsonify (listtype)

Bhoom! наконец-то получил ожидаемый результат, Изображение 929

0

Может сделать простой цикл с проверкой типов:

with open("jsondontdoit.json", 'w') as fp:
    for key in bests.keys():
        if type(bests[key]) == np.ndarray:
            bests[key] = bests[key].tolist()
            continue
        for idx in bests[key]:
            if type(bests[key][idx]) == np.ndarray:
                bests[key][idx] = bests[key][idx].tolist()
    json.dump(bests, fp)
    fp.close()
0

Все остальные кодировщики кажутся слишком сложными. проверьте, если объект из модуля numpy использует numpy.item, он работает для любого конкретного типа numpy.

import numpy as np
import json

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if type(obj).__module__ == np.__name__:
            if isinstance(obj, np.ndarray):
                return obj.tolist()
            else:
                return obj.item()
        return json.JSONEncoder.default(self, obj)

dumped = json.dumps(data, cls=NumpyEncoder)
0

Это другой ответ, но это может помочь людям, которые пытаются сохранить данные, а затем читать их снова.
Существует hickle, которая быстрее, чем рассол и легче.
Я попытался сохранить и прочитать его в дампе соски, но, читая, было много проблем и потрачено впустую на час, но до сих пор не нашел решения, хотя я работал над своими данными, чтобы создать чат-бот.

vec_x и vec_y - массивы numpy:

data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )

Затем вы просто прочитали его и выполните операции:

data2 = hkl.load( 'new_data_file.hkl' )
0

Вот реализация, которая работает для меня и удаляет все nans (предполагая, что это простой объект (список или dict)):

from numpy import isnan

def remove_nans(my_obj, val=None):
    if isinstance(my_obj, list):
        for i, item in enumerate(my_obj):
            if isinstance(item, list) or isinstance(item, dict):
                my_obj[i] = remove_nans(my_obj[i], val=val)

            else:
                try:
                    if isnan(item):
                        my_obj[i] = val
                except Exception:
                    pass

    elif isinstance(my_obj, dict):
        for key, item in my_obj.iteritems():
            if isinstance(item, list) or isinstance(item, dict):
                my_obj[key] = remove_nans(my_obj[key], val=val)

            else:
                try:
                    if isnan(item):
                        my_obj[key] = val
                except Exception:
                    pass

    return my_obj
0

Кроме того, некоторая очень интересная информация по спискам против массивов в Python ~ > Python List vs. Array - когда использовать?

Можно заметить, что как только я конвертирую свои массивы в список, прежде чем сохранять его в JSON файле, в моем развертывании сейчас все равно, как только я прочитаю этот файл JSON для использования позже, я могу продолжать использовать его в списке (в отличие от преобразования его в массив).

И на самом деле выглядит лучше (на мой взгляд) на экране как список (разделенный запятой) по сравнению с массивом (без запятой) таким образом.

Используя метод @travelingbones.tolist() выше, я использовал как таковой (улавливая несколько ошибок, которые я нашел):

СОХРАНЯЙТЕ СЛОВАРЬ

def writeDict(values, name):
    writeName = DIR+name+'.json'
    with open(writeName, "w") as outfile:
        json.dump(values, outfile)

ЧИТАЙТЕ СЛОВАРЬ

def readDict(name):
    readName = DIR+name+'.json'
    try:
        with open(readName, "r") as infile:
            dictValues = json.load(infile)
            return(dictValues)
    except IOError as e:
        print(e)
        return('None')
    except ValueError as e:
        print(e)
        return('None')

Надеюсь, это поможет!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню