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?


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)

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)

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

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 .


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)

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

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

3

Anda juga bisa menggunakan defaultargumen misalnya:

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

json.dump(data, default=myconverter)

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!


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

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

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

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)

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.