Array NumPy bukan JSON yang dapat serial

247

Setelah membuat array NumPy, dan menyimpannya sebagai variabel konteks Django, saya menerima galat berikut saat memuat laman web:

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

Apa artinya ini?

Karnivaurus
sumber
19
Ini berarti bahwa di suatu tempat, ada sesuatu yang mencoba untuk membuang array numpy menggunakan jsonmodul. Tetapi numpy.ndarraybukan tipe yang jsontahu bagaimana menangani. Anda harus menulis serializer Anda sendiri, atau (lebih sederhana) hanya meneruskan list(your_array)ke apa pun yang menulis json.
mgilson
24
Catatan list(your_array)tidak akan selalu berfungsi karena mengembalikan int numpy, bukan int asli. Gunakan your_array.to_list()sebagai gantinya.
ashishsingal
18
catatan tentang komentar @ ashishsingal, itu seharusnya your_array.tolist (), bukan to_list ().
vega

Jawaban:

289

Saya secara teratur "jsonify" np.arrays. Coba gunakan metode ".tolist ()" pada array terlebih dahulu, seperti ini:

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

Untuk "unjsonify" penggunaan array:

obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)
travelingbones
sumber
2
Mengapa hanya bisa disimpan sebagai daftar daftar?
Nikhil Prabhu
Saya tidak tahu, tetapi saya berharap tipe np.array memiliki metadata yang tidak cocok dengan json (misalnya mereka menentukan tipe data dari setiap entri seperti float)
travelingbones
1
Saya mencoba metode Anda, tetapi tampaknya program itu macet tolist().
Harvett
2
@ Frankliuao Saya menemukan alasannya adalah bahwa tolist()dibutuhkan banyak waktu ketika data besar.
Harvett
3
@NikhilPrabhu JSON adalah Notasi Objek Javascript, dan oleh karena itu hanya dapat mewakili konstruksi dasar dari bahasa javascript: objek (analog dengan python dicts), array (analog dengan daftar python), angka, boolean, string, dan nulls (analog dengan python Nones ). Array numpy bukan salah satu dari hal-hal itu, dan karenanya tidak dapat diserialisasi ke JSON. Beberapa dapat dikonversi ke bentuk seperti JSO (daftar daftar), yang merupakan jawaban dari jawaban ini.
Chris L. Barnes
224

Simpan JSON sebagai numpy.ndarray atau komposisi daftar bersarang.

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], [4, 5, 6]])
print(a.shape)
json_dump = json.dumps({'a': a, 'aa': [2, (2, 3, 4), a], 'bb': [2]}, cls=NumpyEncoder)
print(json_dump)

Akan menghasilkan:

(2, 3)
{"a": [[1, 2, 3], [4, 5, 6]], "aa": [2, [2, 3, 4], [[1, 2, 3], [4, 5, 6]]], "bb": [2]}

Untuk memulihkan dari JSON:

json_load = json.loads(json_dump)
a_restored = np.asarray(json_load["a"])
print(a_restored)
print(a_restored.shape)

Akan menghasilkan:

[[1 2 3]
 [4 5 6]]
(2, 3)
karlB
sumber
26
Ini harus menjadi cara yang lebih tinggi, itu adalah cara umum yang dapat diabstraksikan dan dilakukan secara benar. Terima kasih!
thclark
1
Apakah ada cara sederhana untuk mendapatkan ndarray kembali dari daftar?
DarksteelPenguin
4
@DarksteelPenguin yang Anda cari numpy.asarray()?
aeolus
2
Jawaban ini luar biasa dan dapat dengan mudah diperluas untuk membuat serialisasi nilai float32 dan np.float64 yang bersambung juga sebagai json:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
Bensge
Solusi ini menghindari Anda untuk memasukkan secara manual setiap array numpy ke daftar.
eduardosufan
43

Anda dapat menggunakan Panda :

import pandas as pd
pd.Series(your_array).to_json(orient='values')
John Zwinck
sumber
6
Bagus! Dan saya pikir untuk np.array 2D itu akan menjadi sesuatu seperti pd.DataFrame(your_array).to_json('data.json', orient='split').
nix
2
Disimpan hari itu. Terima kasih
anurag
38

Saya menemukan solusi terbaik jika Anda memiliki array numpy bersarang di kamus:

import json
import numpy as np

class NumpyEncoder(json.JSONEncoder):
    """ Special json encoder for numpy types """
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        elif isinstance(obj, np.floating):
            return float(obj)
        elif isinstance(obj, np.ndarray):
            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)

Terima kasih untuk pria ini .

tsveti_iko
sumber
Terima kasih atas jawaban bermanfaatnya! Saya menulis atribut ke file json, tetapi sekarang saya mengalami kesulitan membaca kembali parameter untuk Regresi Logistik. Apakah ada 'decoder' untuk file json yang disimpan ini?
TTZ
Tentu saja, untuk membaca bagian jsonbelakang Anda dapat menggunakan ini with open(path, 'r') as f: data = json.load(f):, yang mengembalikan kamus dengan data Anda.
tsveti_iko
Itu untuk membaca jsonfile dan kemudian deserialize outputnya Anda dapat menggunakan ini:data = json.loads(data)
tsveti_iko
Saya harus menambahkan ini untuk menangani datatype byte .. dengan asumsi semua byte adalah utf-8 string. isif elif (obj, (bytes,)): return obj.decode ("utf-8")
Soichi Hayashi
+1. Mengapa kita memerlukan baris "return json.JSONEncoder.default (self, obj)" di akhir "def default (self, obj)"?
Hans
22

Gunakan json.dumps defaultkwarg:

default harus berupa fungsi yang dipanggil untuk objek yang tidak dapat diserialisasi.

Dalam defaultfungsi periksa apakah objek dari modul numpy, jika demikian baik digunakan ndarray.tolistuntuk ndarrayatau digunakan .itemuntuk jenis spesifik numpy lainnya.

import numpy as np

def default(obj):
    if type(obj).__module__ == np.__name__:
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        else:
            return obj.item()
    raise TypeError('Unknown type:', type(obj))

dumped = json.dumps(data, default=default)
moshevi
sumber
Apa peran garis di type(obj).__module__ == np.__name__: sana? Tidakkah cukup untuk memeriksa contoh?
Ramon Martinez
@RamonMartinez, untuk mengetahui bahwa objek tersebut adalah objek numpy, cara ini dapat saya gunakan .itemuntuk hampir semua objek numpy. defaultfungsi dipanggil untuk semua jenis json.dumpsupaya yang tidak dikenal untuk membuat cerita bersambung. bukan hanya numpy
moshevi
5

Ini tidak didukung secara default, tetapi Anda dapat membuatnya bekerja dengan mudah! Ada beberapa hal yang ingin Anda encode jika Anda ingin data yang sama persis kembali:

  • Data itu sendiri, yang bisa Anda dapatkan obj.tolist()sebagai @travelingbones yang disebutkan. Terkadang ini mungkin cukup baik.
  • Tipe data. Saya merasa ini penting dalam beberapa kasus.
  • Dimensi (tidak harus 2D), yang dapat diturunkan dari di atas jika Anda menganggap inputnya memang selalu berupa kotak 'persegi panjang'.
  • Urutan memori (baris-atau kolom-utama). Ini tidak sering penting, tetapi kadang-kadang memang demikian (misalnya kinerja), jadi mengapa tidak menyimpan semuanya?

Selain itu, larik numpy Anda dapat menjadi bagian dari struktur data Anda, misalnya Anda memiliki daftar dengan beberapa matriks di dalamnya. Untuk itu Anda dapat menggunakan pembuat enkode khusus yang pada dasarnya melakukan hal di atas.

Ini harus cukup untuk mengimplementasikan solusi. Atau Anda dapat menggunakan trik json yang melakukan hal ini (dan mendukung berbagai jenis lainnya) (penafian: Saya berhasil).

pip install json-tricks

Kemudian

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))
Menandai
sumber
3

Saya memiliki masalah yang sama dengan kamus bersarang dengan beberapa numpy.ndarrays di dalamnya.

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
JLT
sumber
3

Anda juga bisa menggunakan defaultargumen misalnya:

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

json.dump(data, default=myconverter)
steco
sumber
1

Juga, beberapa informasi yang sangat menarik lebih lanjut tentang daftar vs array dalam Python ~> Daftar Python vs. Array - kapan harus digunakan?

Dapat dicatat bahwa setelah saya mengubah array saya menjadi daftar sebelum menyimpannya dalam file JSON, dalam penerapan saya sekarang, setelah saya membaca file JSON untuk digunakan nanti, saya dapat terus menggunakannya dalam bentuk daftar (seperti menentang mengubahnya kembali ke array).

DAN sebenarnya terlihat lebih bagus (menurut saya) di layar sebagai daftar (dipisahkan koma) vs array (tidak dipisahkan koma) dengan cara ini.

Menggunakan metode .tolist () @ travelingbones di atas, saya telah menggunakannya (menangkap beberapa kesalahan yang saya temukan juga):

SIMPAN KAMUS

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

BACA KAMUS

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')

Semoga ini membantu!

ntk4
sumber
1

Berikut ini adalah implementasi yang berfungsi untuk saya dan menghapus semua nans (dengan asumsi ini adalah objek sederhana (daftar atau dikt)):

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
Roei Bahumi
sumber
1

Ini adalah jawaban yang berbeda, tetapi ini mungkin membantu untuk membantu orang yang mencoba menyimpan data dan kemudian membacanya lagi.
Ada hickle yang lebih cepat dari pada acar dan lebih mudah.
Saya mencoba untuk menyimpan dan membacanya di acar dump tetapi ketika membaca ada banyak masalah dan menghabiskan satu jam dan masih tidak menemukan solusi meskipun saya sedang mengerjakan data saya sendiri untuk membuat bot obrolan.

vec_xdan vec_yarray numpy:

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

Kemudian Anda baru saja membacanya dan melakukan operasi:

data2 = hkl.load( 'new_data_file.hkl' )
KS HARSHA
sumber
1

Dapat melakukan simpel untuk loop dengan memeriksa jenis:

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()
Robert GRZELKA
sumber
1

gunakan NumpyEncoder itu akan memproses json dump berhasil. Tanpa melempar - array NumPy tidak JSON serializable

import numpy as np
import json
from numpyencoder import NumpyEncoder
arr = array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) 
json.dumps(arr,cls=NumpyEncoder)
krishna kumar mishra
sumber
0

TypeError: array ([[0,46872085, 0,67374235, 1.0218339, 0,13210179, 0,5440686, 0,9140083, 0,58720225, 0,2199381]], dtype = float32) bukan JSON serializable

Kesalahan yang disebutkan di atas terlempar ketika saya mencoba meneruskan daftar data ke model.predict () ketika saya mengharapkan respons dalam format 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)

Tapi untungnya menemukan petunjuk untuk menyelesaikan kesalahan yang melempar. Serialisasi objek hanya berlaku untuk konversi berikut Pemetaan harus dengan cara mengikuti objek - array dict - daftar string - string integer - integer

Jika Anda gulir ke atas untuk melihat nomor baris 10 prediksi = loaded_model.predict (d) di mana baris kode ini menghasilkan output tipe array data, ketika Anda mencoba mengubah array ke format json, itu tidak mungkin.

Akhirnya saya menemukan solusinya hanya dengan mengonversi keluaran yang diperoleh ke daftar jenis dengan mengikuti baris kode

prediction = loaded_model.predict (d)
listtype = prediction.tolist () return jsonify (listtype)

Bhoom! akhirnya mendapat hasil yang diharapkan, masukkan deskripsi gambar di sini

Poornima Subramani Naidu
sumber