อาร์เรย์ NumPy ไม่ใช่ JSON ที่ปรับแต่งได้


247

หลังจากสร้างอาร์เรย์ NumPy และบันทึกเป็นตัวแปรบริบท Django ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อโหลดหน้าเว็บ:

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

สิ่งนี้หมายความว่า?


19
หมายความว่ามีบางสิ่งที่พยายามถ่ายโอนอาเรย์ numpy โดยใช้jsonโมดูล แต่numpy.ndarrayไม่ใช่ประเภทที่jsonรู้วิธีจัดการ คุณจะต้องเขียน serializer ของคุณเองหรือเพียงแค่ส่งlist(your_array)สิ่งที่เขียน json
mgilson

24
หมายเหตุlist(your_array)จะไม่สามารถใช้งานได้ตลอดเวลาเนื่องจากจะส่งคืน ints ที่เป็น numpy ไม่ใช่ ints ดั้งเดิม ใช้your_array.to_list()แทน
ashishsingal

18
หมายเหตุเกี่ยวกับความคิดเห็นของ @ ashishsingal ควรเป็น your_array.tolist () ไม่ใช่ to_list ()
vega

คำตอบ:


289

ฉันเป็นประจำ "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)

3
เหตุใดจึงสามารถจัดเก็บเป็นรายการได้เท่านั้น
Nikhil Prabhu

ผมไม่ทราบ แต่ผมคาดหวังว่าประเภท np.array มีเมตาดาต้าที่ไม่พอดีกับ JSON (เช่นที่พวกเขาระบุชนิดข้อมูลของรายการเช่นลอยแต่ละคน)
travelingbones

2
ฉันพยายามที่วิธีการของคุณ tolist()แต่ดูเหมือนว่าโปรแกรมที่
Harvett

3
@frankliuao ฉันพบเหตุผลคือtolist()ต้องใช้เวลาจำนวนมากเมื่อข้อมูลมีขนาดใหญ่
Harvett

4
@NikhilPrabhu JSON เป็นสัญลักษณ์วัตถุ Javascript และสามารถแสดงโครงสร้างพื้นฐานจากภาษาจาวาสคริปต์: วัตถุ (คล้ายกับ python dicts), อาร์เรย์ (คล้ายกับรายการ python), ตัวเลข, booleans, สตริงและ null (คล้ายกับ python Nones) ) อาร์เรย์ที่มีจำนวนมากไม่ใช่สิ่งเหล่านั้นดังนั้นจึงไม่สามารถต่อเนื่องเป็น JSON ได้ บางรายการสามารถแปลงเป็นรูปแบบที่เหมือน JSO (รายการของรายการ) ซึ่งเป็นคำตอบที่ได้
Chris L. Barnes

225

จัดเก็บเป็น JSON เป็น numpy.ndarray หรือองค์ประกอบที่ซ้อนกัน

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)

จะส่งออก:

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

ในการกู้คืนจาก JSON:

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

จะส่งออก:

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

26
นี่ควรจะเป็นวิธีที่สูงขึ้นในคณะกรรมการมันเป็นวิธีทั่วไปและเป็นนามธรรมอย่างถูกต้องในการทำเช่นนี้ ขอบคุณ!
thclark

2
มีวิธีง่าย ๆ ในการรับ ndarray กลับจากรายการหรือไม่
DarksteelPenguin

5
@DarksteelPenguin คุณกำลังมองหาnumpy.asarray()?
aeolus

3
คำตอบนี้ดีมากและสามารถขยายได้อย่างง่ายดายเพื่ออนุกรม numpy float32 และค่า np.float64 เป็น json เช่นกัน:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
14909

วิธีนี้จะหลีกเลี่ยงการที่คุณจะส่งรายการ numpy array ไปยังรายการด้วยตนเอง
eduardosufan

44

คุณสามารถใช้หมีแพนด้า :

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

6
ที่ดี! และผมคิดว่าสำหรับ 2D np.array pd.DataFrame(your_array).to_json('data.json', orient='split')มันจะเป็นสิ่งที่ชอบ
ห้าม

2
บันทึกวัน ขอบคุณ
anurag

40

ฉันพบทางออกที่ดีที่สุดหากคุณมีอาร์เรย์ 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.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)

ขอบคุณผู้ชายคนนี้


ขอบคุณสำหรับคำตอบที่เป็นประโยชน์! ฉันเขียนคุณสมบัติไปยังไฟล์ json แต่ตอนนี้ฉันมีปัญหาในการอ่านพารามิเตอร์สำหรับ Logistic Regression มี 'ตัวถอดรหัส' สำหรับไฟล์ json ที่บันทึกไว้นี้หรือไม่
TTZ

แน่นอนว่าเมื่อต้องการอ่านjsonหลังคุณสามารถใช้สิ่งนี้: with open(path, 'r') as f: data = json.load(f)ซึ่งส่งคืนพจนานุกรมพร้อมข้อมูลของคุณ
tsveti_iko

สำหรับการอ่านjsonไฟล์และจากนั้นเพื่อdata = json.loads(data)
ยกเลิกการซีเรียลไลซ์

ฉันต้องเพิ่มสิ่งนี้เพื่อจัดการประเภทข้อมูลไบต์ .. สมมติว่าไบต์ทั้งหมดเป็นสตริง utf-8 elif isinstance (obj, (bytes,)): return obj.decode ("utf-8")
Soichi Hayashi

+1 ทำไมเราต้องการบรรทัด "return json.JSONEncoder.default (self, obj)" ที่ส่วนท้ายของ "def default (self, obj)"?
ฮันส์

23

ใช้json.dumps defaultkwarg:

ค่าเริ่มต้นควรเป็นฟังก์ชันที่เรียกใช้วัตถุที่ไม่สามารถต่อเนื่องกันได้

ในdefaultฟังก์ชั่นการตรวจสอบว่าวัตถุมาจากโมดูลก้อนถ้าเป็นเช่นนั้นใช้ndarray.tolistสำหรับndarrayหรือใช้.itemสำหรับประเภทที่เฉพาะเจาะจงอื่น ๆ numpy

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__: นั่นคืออะไร จะไม่พอที่จะตรวจสอบอินสแตนซ์หรือไม่
Ramon Martinez

@RamonMartinez รู้ว่าวัตถุนั้นเป็นวัตถุแบบ numpy วิธีนี้ฉันสามารถใช้.itemกับวัตถุ numpy เกือบทุกชนิด defaultฟังก์ชันถูกเรียกใช้สำหรับประเภทที่ไม่รู้จักทั้งหมดที่json.dumpsพยายามทำให้เป็นอันดับ ไม่เพียงแค่
ก้อนโต

5

ค่าเริ่มต้นนี้ไม่ได้รับการสนับสนุน แต่คุณสามารถทำให้มันใช้งานได้ง่าย! มีหลายสิ่งที่คุณต้องการเข้ารหัสหากคุณต้องการให้ข้อมูลเดิมกลับคืนมา:

  • ข้อมูลเองซึ่งคุณสามารถรับได้ด้วย 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))

3

ฉันมีปัญหาคล้ายกันกับพจนานุกรมที่ซ้อนกันซึ่งมี 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

3

คุณสามารถใช้defaultอาร์กิวเมนต์ตัวอย่างเช่น:

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

json.dump(data, default=myconverter)

1

นอกจากนี้ยังมีข้อมูลที่น่าสนใจเพิ่มเติมเกี่ยวกับรายการและอาร์เรย์ใน Python ~> รายการ Python เทียบกับ Array - เมื่อใดควรใช้

อาจสังเกตได้ว่าเมื่อฉันแปลงอาร์เรย์ของฉันเป็นรายการก่อนที่จะบันทึกในไฟล์ JSON ในการปรับใช้ของฉันตอนนี้เมื่อฉันอ่านไฟล์ JSON นั้นเพื่อใช้ในภายหลังฉันสามารถใช้มันในรูปแบบรายการต่อไป ตรงข้ามกับการแปลงกลับเป็นอาร์เรย์)

และจริง ๆ แล้วดูดีกว่า (ในความคิดของฉัน) บนหน้าจอเป็นรายการ (คั่นด้วยเครื่องหมายจุลภาค) เทียบกับอาร์เรย์ (ไม่ใช่คั่นด้วยเครื่องหมายจุลภาค) ด้วยวิธีนี้

การใช้วิธีการ @ .toolbones's .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')

หวังว่านี่จะช่วยได้!


1

นี่คือการใช้งานที่เหมาะกับฉันและลบ 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

1

นี่เป็นคำตอบที่แตกต่างกัน แต่สิ่งนี้อาจช่วยให้ผู้ที่พยายามบันทึกข้อมูลจากนั้นอ่านอีกครั้ง
มี hickle ซึ่งเร็วกว่าดองและง่ายขึ้น
ฉันพยายามบันทึกและอ่านมันใน pickle dump แต่ในขณะที่อ่านมีปัญหามากมายและเสียเวลาหนึ่งชั่วโมงและยังไม่พบวิธีแก้ปัญหาแม้ว่าฉันกำลังทำงานกับข้อมูลของตัวเองเพื่อสร้างบอทแชท

vec_xและvec_yเป็นอาร์เรย์ numpy:

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

จากนั้นคุณก็อ่านมันและดำเนินการ:

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

1

อาจทำได้ง่ายสำหรับลูปที่มีประเภทการตรวจสอบ:

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 มันจะประมวลผลการถ่ายโอนข้อมูล json ประสบความสำเร็จโดยไม่ต้องโยน - อาร์เรย์ NumPy ไม่ JSON ต่อเนื่องได้

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) ไม่ได้เรียงลำดับ 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 - สตริงรายการ - จำนวนเต็มสตริง - จำนวนเต็ม

หากคุณเลื่อนขึ้นเพื่อดูหมายเลขบรรทัด 10 การทำนาย = load_model.predict (d) ที่บรรทัดของรหัสนี้สร้างผลลัพธ์ของประเภทข้อมูลอาร์เรย์ประเภทเมื่อคุณพยายามแปลงอาร์เรย์เป็นรูปแบบ json เป็นไปไม่ได้

ในที่สุดฉันก็พบวิธีแก้ปัญหาเพียงแค่แปลงผลลัพธ์ที่ได้รับไปยังรายการประเภทโดยบรรทัดของรหัสต่อไปนี้

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

Bhoom! ในที่สุดก็ได้ผลลัพธ์ที่คาดหวัง ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.