NumPy dizisi JSON serileştirilebilir değil


247

Bir NumPy dizisi oluşturduktan ve bir Django bağlam değişkeni olarak kaydettikten sonra, web sayfasını yüklerken aşağıdaki hatayı alıyorum:

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

Ne anlama geliyor?


19
Bir yerde, bir şey jsonmodülü kullanarak numpy dizisini boşaltmaya çalışıyor demektir . Ancak nasıl ele alınacağını bilen numpy.ndarraybir tür değildir json. Ya kendi serileştiricinizi yazmanız gerekecek, ya da (daha basit) sadece list(your_array)json'u yazan her şeye geçmeniz gerekecek .
mgilson

24
Not list(your_array)her zaman çalışmayacak, yerel girişler değil, sayısal girişler döndürecektir. your_array.to_list()Bunun yerine kullanın .
ashishsingal

18
@ ashishsingal'ın yorumu hakkında bir not, to_list () değil, your_array.tolist () olmalıdır.
vega

Yanıtlar:


289

Ben düzenli olarak np.arrays "jsonify". Önce dizilerde ".tolist ()" yöntemini kullanmayı deneyin, şöyle:

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

Diziyi "unjsonify" etmek için şunu kullanın:

obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)

3
Neden sadece liste listesi olarak saklanabilir?
Nikhil Prabhu

Bilmiyorum ama np.array türleri json sığmayan meta veri (örneğin float gibi her girişin veri türünü belirtin) bekliyoruz
travelling

2
Metodunu denedim, ama programın sıkışmış gibi görünüyor tolist().
Harvett

3
@frankliuao Ben tolist()veri büyük olduğunda çok zaman alır nedeni bulundu .
Harvett

4
@NikhilPrabhu JSON, Javascript Nesne Gösterimi'dir ve bu nedenle yalnızca javascript dilinden temel yapıları temsil edebilir: nesneler (python diktatörlerine benzer), diziler (python listelerine benzer), sayılar, booleans, dizeler ve null'lar (python Nones'e benzer) ). Numpy dizileri bunlardan herhangi biri değildir ve bu nedenle JSON'a serileştirilemez. Bazıları bu cevabın yaptığı JSO benzeri bir forma (liste listesi) dönüştürülebilir.
Chris L. Barnes

225

JSON olarak bir numpy.ndarray veya herhangi bir iç içe liste oluşturma depolayın.

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)

Çıktı olacak:

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

JSON'dan geri yüklemek için:

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

Çıktı olacak:

[[1 2 3]
 [4 5 6]]
(2, 3)

26
Bu, tahtadan çok daha yüksek olmalı, bunu yapmanın genel ve uygun şekilde soyutlanmış yolu. Teşekkürler!
thclark

2
Ndarray'ı listeden geri almanın basit bir yolu var mı?
18:47

5
@DarksteelPenguin arıyorsunuz numpy.asarray()?
aeolus

3
Bu cevap harika ve numpy float32 ve np.float64 değerlerini json olarak serileştirmek için kolayca genişletilebilir:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
Bensge

Bu çözüm, listelenecek her numpy diziyi manuel olarak dökmenizi önler.
eduardosufan

44

Pandaları kullanabilirsiniz :

import pandas as pd
pd.Series(your_array).to_json(orient='values')

6
Harika! Bence 2D np.array için böyle bir şey olacak pd.DataFrame(your_array).to_json('data.json', orient='split').
nix

2
Günü kurtardım. Teşekkürler
anurag

40

Bir sözlükte numpy dizileri iç içe geçtiyseniz en iyi çözümü buldum:

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)

Bu adama teşekkürler .


Yararlı cevap için teşekkürler! Öznitelikleri bir json dosyasına yazdım, ancak şimdi Lojistik Regresyon parametrelerini okumada sorun yaşıyorum. Bu kaydedilmiş json dosyası için bir 'kod çözücü' var mı?
TTZ

Tabii ki, jsongeri okumak için kullanabilirsiniz: with open(path, 'r') as f: data = json.load(f)verilerinizle bir sözlük döndürür.
tsveti_iko

Bu jsondosyayı okumak ve çıktısını serileştirmek için bunu kullanabilirsiniz:data = json.loads(data)
tsveti_iko

Ben tüm bayt utf-8 dize varsayalım bayt veri türü işlemek için eklemek zorunda kaldı. elif isinstance (obj, (bytes,)): dönüş obj.decode ("utf-8")
Soichi Hayashi

+1. Neden "def default (self, obj)" sonunda "return json.JSONEncoder.default (self, obj)" satırına ihtiyacımız var?
Hans

23

json.dumps defaultKwarg kullanın :

varsayılan, başka şekilde serileştirilemeyen nesneler için çağrılan bir işlev olmalıdır.

Olarak defaultişlev kontrolünün amacı, modül Numpy arasında olması ya da kullanım Öyleyse ndarray.tolistbir için ndarrayya da kullanım .itembaşka numpy belirli tür için.

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)

type(obj).__module__ == np.__name__: Buradaki çizginin rolü nedir ? Örneği kontrol etmek yeterli olmaz mı?
Ramon Martinez

@RamonMartinez, nesnenin numpy bir nesne olduğunu bilmek, bu şekilde .itemhemen hemen her numpy nesne için kullanabilirsiniz . serileştirme girişimleri için defaultbilinmeyen türlerin tümü için işlev çağrılır json.dumps. sadece numpy değil
moshevi

5

Bu varsayılan olarak desteklenmez, ancak oldukça kolay çalışmasını sağlayabilirsiniz! Aynı verileri geri almak istiyorsanız kodlamak isteyeceğiniz birkaç şey vardır:

  • Elde edebileceğiniz verinin kendisi obj.tolist() @travelingbones . Bazen bu yeterince iyi olabilir.
  • Veri türü. Bunun bazı durumlarda önemli olduğunu düşünüyorum.
  • Girdinin gerçekten her zaman bir 'dikdörtgen' ızgara olduğunu varsayarsanız, yukarıdan türetilebilecek boyut (2B olması zorunlu değildir).
  • Bellek sırası (satır veya sütun ana). Bu çoğu zaman önemli değildir, ancak bazen önemlidir (örneğin performans), neden her şeyi kurtarmıyorsunuz?

Ayrıca, numpy diziniz veri yapınızın bir parçası olabilir, örneğin içinde bazı matrislerin bulunduğu bir listeniz var. Bunun için temelde yukarıdakileri yapan özel bir kodlayıcı kullanabilirsiniz.

Bu bir çözüm uygulamak için yeterli olmalıdır. Ya da sadece bunu yapan json-tricks kullanabilirsiniz (ve diğer çeşitli türleri destekler) (feragat: Ben yaptım).

pip install json-tricks

Sonra

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

İçinde bazı numpy.ndarrays ile iç içe bir sözlük ile benzer bir sorun vardı.

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

defaultÖrneğin, bağımsız değişkeni de kullanabilirsiniz :

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

json.dump(data, default=myconverter)

1

Ayrıca, Python ~> Python List vs Array listeler - diziler hakkında daha ilginç bazı bilgiler - ne zaman kullanılır?

Dizilerimi bir JSON dosyasına kaydetmeden önce bir listeye dönüştürdüğümde, şu anda dağıtımımda zaten, o JSON dosyasını daha sonra kullanmak için okuduğumda, bir liste formunda ( bir diziye dönüştürmek yerine).

VE aslında (bence) ekranda bir dizi (virgülle ayrılmış) vs bir dizi (virgülle ayrılmış değil) bu şekilde ekranda güzel görünüyor.

Yukarıdaki @ travelingbones .tolist () yöntemini kullanarak, ben böyle kullanıyorum (ben de buldum birkaç hata yakalamak):

SÖZLÜĞÜ KAYDET

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

SÖZLÜĞÜ OKUYUN

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

Bu yardımcı olur umarım!


1

İşte benim için çalışan ve tüm nans'ları kaldıran bir uygulama (bunların basit nesne (liste veya dikte) olduğu varsayılır):

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

Bu farklı bir yanıttır, ancak bu, verileri kaydetmeye ve sonra tekrar okumaya çalışan kişilere yardımcı olabilir.
Turşudan daha hızlı ve daha kolay bir hickle var.
Turşu dökümünde kaydetmeye ve okumaya çalıştım ama okurken çok fazla sorun vardı ve bir saat harcadım ve hala sohbet botu oluşturmak için kendi verilerim üzerinde çalışıyordum.

vec_x ve vec_y numpy dizileridir:

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

Sonra sadece okuyun ve işlemleri gerçekleştirin:

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

1

Kontrol tipleriyle döngü için basit olabilir:

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

NumpyEncoder kullanın json dökümü başarıyla işleyecektir. atmadan - NumPy dizi JSON serileştirilebilir değil

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: dizi ([[0.46872085, 0.67374235, 1.0218339, 0.13210179, 0.5440686, 0.9140083, 0.58720225, 0.2199381]], dtype = float32) JSON serileştirilemez

Yukarıda belirtilen hata, ben json biçiminde yanıt bekliyordum zaman veri listesi model.predict () geçmek için atılmış oldu.

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

Ama neyse ki fırlatma hatasını çözmek için ipucu buldu Nesnelerin serileştirilmesi sadece aşağıdaki dönüşüm için geçerlidir Eşleme şu şekilde olmalıdır: nesne - dict dizi - liste string - string integer - integer

Bu kod satırının dizi dizi veri türünün çıktısını oluşturduğu 10 öngörüsü = loaded_model.predict (d) satır numarasını görmek için yukarı kaydırırsanız, diziyi json biçimine dönüştürmeye çalıştığınızda bu mümkün değildir

Sonunda sadece kod satırlarını takip ederek elde edilen çıktıyı tip listesine dönüştürerek çözümü buldum

prediction = loaded_model.predict (d)
listtype = prediction.tolist () dönüş jsonify (listtype)

Bhoom! sonunda beklenen çıktıyı aldı, resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.