Mảng NumPy không được tuần tự hóa JSON


247

Sau khi tạo mảng NumPy và lưu nó dưới dạng biến ngữ cảnh Django, tôi nhận được lỗi sau khi tải trang web:

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

Điều đó có nghĩa là gì?


19
Nó có nghĩa là ở đâu đó, một cái gì đó đang cố gắng kết xuất một mảng numpy bằng cách sử dụng jsonmô-đun. Nhưng numpy.ndarraykhông phải là một loại jsonbiết cách xử lý. Bạn sẽ cần phải viết serializer của riêng bạn, hoặc (đơn giản hơn) chỉ cần chuyển list(your_array)sang bất cứ điều gì đang viết json.
mgilson

24
Lưu ý list(your_array)sẽ không luôn luôn hoạt động vì nó trả về int numpy, không phải ints gốc. Sử dụng your_array.to_list()thay thế.
ashishsingal

18
một lưu ý về nhận xét của @ ashishsingal, đó phải là your_array.tolist (), không phải to_list ().
vega

Câu trả lời:


289

Tôi thường xuyên "jsonify" np.arrays. Trước tiên, hãy thử sử dụng phương thức ".tolist ()" trên các mảng, như sau:

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", sử dụng mảng:

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

2
Tại sao nó chỉ có thể được lưu trữ như một danh sách các danh sách?
Nikhil Bohhu

Tôi không biết nhưng tôi hy vọng các loại np.array có siêu dữ liệu không phù hợp với json (ví dụ: chúng chỉ định loại dữ liệu của từng mục như float)
travelling

1
Tôi đã thử phương pháp của bạn, nhưng có vẻ như chương trình bị kẹt tolist().
Harvestett

2
@frankliuao Tôi tìm thấy lý do là tolist()mất một lượng lớn thời gian khi dữ liệu lớn.
Harvestett

3
@NikhilPrabhu JSON là Ký hiệu đối tượng Javascript và do đó chỉ có thể biểu thị các cấu trúc cơ bản từ ngôn ngữ javascript: các đối tượng (tương tự như python dicts), mảng (tương tự danh sách python), số, booleans, chuỗi và null (tương tự với python Nones ). Mảng Numpy không phải là bất kỳ thứ gì trong số đó, và do đó không thể được tuần tự hóa thành JSON. Một số có thể được chuyển đổi thành một dạng giống như JSO (danh sách các danh sách), đó là những gì câu trả lời này làm.
Chris L. Barnes

224

Lưu trữ dưới dạng JSON một numpy.ndarray hoặc bất kỳ thành phần danh sách lồng nhau nào.

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)

Sẽ xuất:

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

Để khôi phục từ JSON:

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

Sẽ xuất:

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

26
Đây phải là cách cao hơn của hội đồng quản trị, đó là cách tổng quát và trừu tượng để làm điều này. Cảm ơn!
thclark

1
Có một cách đơn giản để đưa ndarray trở lại từ danh sách?
DarksteelPenguin

4
@DarksteelPenguin bạn đang tìm kiếm numpy.asarray()?
aeolus

2
Câu trả lời này rất hay và có thể dễ dàng được mở rộng để tuần tự hóa các giá trị float32 và np.float64 như json nữa:if isinstance(obj, np.float32) or isinstance(obj, np.float64): return float(obj)
Bensge

Giải pháp này tránh cho bạn truyền thủ công từng mảng numpy vào danh sách.
eduardosufan

43

Bạn có thể sử dụng gấu trúc :

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

6
Tuyệt quá! Và tôi nghĩ đối với 2D np.array nó sẽ giống như thế pd.DataFrame(your_array).to_json('data.json', orient='split').
nix

2
Đã cứu sống ngày. Cảm ơn
anurag

38

Tôi đã tìm thấy giải pháp tốt nhất nếu bạn có các mảng numpy lồng nhau trong một từ điển:

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)

Cảm ơn anh chàng này .


Cảm ơn câu trả lời hữu ích! Tôi đã viết các thuộc tính cho một tệp json, nhưng hiện đang gặp khó khăn khi đọc lại các tham số cho Hồi quy logistic. Có 'bộ giải mã' cho tệp json đã lưu này không?
TTZ

Tất nhiên, để đọc mặt jsonsau, bạn có thể sử dụng cái này : with open(path, 'r') as f: data = json.load(f), trả về một từ điển với dữ liệu của bạn.
tsveti_iko

Đó là để đọc jsontệp và sau đó để giải tuần tự hóa, bạn có thể sử dụng data = json.loads(data)
tệp

Tôi đã phải thêm điều này để xử lý kiểu dữ liệu byte .. giả sử tất cả các byte là chuỗi utf-8. elif isinstance (obj, (byte,)): return obj.decode ("utf-8")
Soichi Hayashi

+1. Tại sao chúng ta cần dòng "return json.JSONEncoder.default (self, obj)" ở cuối "def default (self, obj)"?
Hans

22

Sử dụng json.dumps defaultkwarg:

mặc định phải là một hàm được gọi cho các đối tượng không thể được tuần tự hóa.

Trong defaultchức năng kiểm tra xem đối tượng là từ mô-đun numpy, nếu vậy hoặc sử dụng ndarray.tolistcho a ndarrayhoặc sử dụng .itemcho bất kỳ loại cụ thể numpy khác.

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)

Vai trò của dòng type(obj).__module__ == np.__name__: ở đó là gì? Nó sẽ không đủ để kiểm tra ví dụ?
Ramon Martinez

@RamonMartinez, để biết rằng đối tượng là một đối tượng numpy, theo cách này tôi có thể sử dụng .itemcho hầu hết mọi đối tượng numpy. defaultHàm được gọi cho tất cả các loại không xác định json.dumpscố gắng tuần tự hóa. không chỉ numpy
moshevi

5

Điều này không được hỗ trợ theo mặc định, nhưng bạn có thể làm cho nó hoạt động khá dễ dàng! Có một số điều bạn sẽ muốn mã hóa nếu bạn muốn trả lại chính xác cùng một dữ liệu:

  • Các dữ liệu mà bạn có thể nhận được obj.tolist()như @travelingbones đã đề cập. Đôi khi điều này có thể là đủ tốt.
  • Kiểu dữ liệu. Tôi cảm thấy điều này rất quan trọng trong một số trường hợp.
  • Kích thước (không nhất thiết phải là 2D), có thể được lấy từ phía trên nếu bạn cho rằng đầu vào thực sự luôn là một lưới 'hình chữ nhật'.
  • Thứ tự bộ nhớ (hàng- hoặc cột chính). Điều này không thường xuyên, nhưng đôi khi nó (ví dụ như hiệu suất), vậy tại sao không lưu tất cả mọi thứ?

Hơn nữa, mảng numpy của bạn có thể là một phần của cấu trúc dữ liệu của bạn, ví dụ: bạn có một danh sách với một số ma trận bên trong. Cho rằng bạn có thể sử dụng một bộ mã hóa tùy chỉnh về cơ bản như trên.

Điều này là đủ để thực hiện một giải pháp. Hoặc bạn có thể sử dụng json-trick chỉ thực hiện điều này (và hỗ trợ nhiều loại khác) (từ chối trách nhiệm: Tôi đã thực hiện).

pip install json-tricks

Sau đó

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

Tôi đã có một vấn đề tương tự với một từ điển lồng nhau với một số numpy.ndarrays trong đó.

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

Bạn cũng có thể sử dụng defaultđối số ví dụ:

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

json.dump(data, default=myconverter)

1

Ngoài ra, một số thông tin rất thú vị về danh sách so với mảng trong Python ~> Danh sách Python so với Mảng - khi nào nên sử dụng?

Có thể lưu ý rằng một khi tôi chuyển đổi các mảng của mình thành một danh sách trước khi lưu nó vào một tệp JSON, thì dù sao tôi cũng sẽ triển khai tệp đó để sử dụng nó trong một dạng danh sách (như trái ngược với việc chuyển đổi nó trở lại một mảng).

AND thực sự trông đẹp hơn (theo ý kiến ​​của tôi) trên màn hình dưới dạng một danh sách (được phân tách bằng dấu phẩy) so với một mảng (không được phân tách bằng dấu phẩy) theo cách này.

Sử dụng phương thức .tolist () của @ travelling () ở trên, tôi đã sử dụng như vậy (bắt một số lỗi tôi cũng đã tìm thấy):

TIẾT KIỆM

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

ĐỌC DICTIONary

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

Hi vọng điêu nay co ich!


1

Đây là một triển khai phù hợp với tôi và loại bỏ tất cả các nans (giả sử đây là các đối tượng đơn giản (danh sách hoặc 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

Đây là một câu trả lời khác nhau, nhưng điều này có thể giúp giúp những người đang cố lưu dữ liệu và sau đó đọc lại.
Có tiếng lạch cạch nhanh hơn dưa chua và dễ dàng hơn.
Tôi đã cố lưu và đọc nó trong thùng rác nhưng trong khi đọc có rất nhiều vấn đề và lãng phí một giờ và vẫn không tìm thấy giải pháp mặc dù tôi đang làm việc trên dữ liệu của riêng mình để tạo bot trò chuyện.

vec_xvec_ylà mảng numpy:

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

Sau đó, bạn chỉ cần đọc nó và thực hiện các hoạt động:

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

1

Có thể làm đơn giản cho vòng lặp với các loại kiểm tra:

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

sử dụng NumpyEncoder, nó sẽ xử lý json dump thành công. Ném ra - mảng NumPy không phải là tuần tự hóa 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

LoạiError: mảng ([[0.46872085, 0.67374235, 1.0218339, 0.13210179, 0.5440686, 0.9140083, 0.58720225, 0.2199381]], dtype = float32) không được tuần tự hóa

Lỗi được đề cập ở trên đã bị ném khi tôi cố chuyển danh sách dữ liệu sang model.predict () khi tôi đang mong đợi phản hồi ở định dạng 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)

Nhưng may mắn tìm thấy gợi ý để giải quyết lỗi đang ném Việc tuần tự hóa các đối tượng chỉ có thể áp dụng cho chuyển đổi sau Ánh xạ phải theo cách sau đối tượng - mảng dict - danh sách chuỗi - số nguyên chuỗi - số nguyên

Nếu bạn cuộn lên để xem dòng số 10 dự đoán = oad_model.predict (d) trong đó dòng mã này đang tạo đầu ra của kiểu dữ liệu mảng kiểu, khi bạn cố gắng chuyển đổi mảng thành định dạng json thì không thể

Cuối cùng tôi đã tìm thấy giải pháp chỉ bằng cách chuyển đổi đầu ra thu được sang danh sách loại bằng các dòng mã sau

dự đoán = oad_model.predict (d)
listtype = dự đoán.tolist () return jsonify (listtype)

Bhoom! cuối cùng đã có đầu ra như mong đợi, nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.