使用Json转储2D Python数组

4

我有一个 numpy 数组,想要用 Json 进行转储。该数组的样式如下:

array([['foo', 'bar', 'something', ...
        'more'],
        ['0.4', '0.7', '0.83', ...
        '0.3', '0.62', '0.51']]

我想将它转储到一个字符串使用Json,如下所示:

foo: 0.4
bar: 0.7
something: 0.51
...
我已经尝试过以下方法:
import jason
my_string = json.dumps(my_array)

但是它报错了:

"not JSON serializable"
有没有关于如何使用Json格式将这个内容输出到字符串的想法? 更新: 请注意,我关心顺序,行应按以下顺序打印:
array[0,0] : array[0,1]
array[1,0] : array[1,1]
array[2,0] : array[2,1]
# etc ...

你的数组索引在末尾是不正确的。对于这样的二维数组,语法是array[row][column],由于您只有两行,第一个索引的最大值将是1 - martineau
5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
7

在我使用更大的1024x1002浮点数组时,对我有效的方法是将其转换为base64编码。

def Base64Encode(ndarray):
    return json.dumps([str(ndarray.dtype),base64.b64encode(ndarray),ndarray.shape])
def Base64Decode(jsonDump):
    loaded = json.loads(jsonDump)
    dtype = np.dtype(loaded[0])
    arr = np.frombuffer(base64.decodestring(loaded[1]),dtype)
    if len(loaded) > 2:
        return arr.reshape(loaded[2])
    return arr

''' just to compare '''
def SimpleEncode(ndarray):
    return json.dumps(ndarray.tolist())
def SimpleDecode(jsonDump):
    return np.array(json.loads(jsonDump))

ipython %timeit 的结果非常清晰,指向了base64:

arr = np.random.random_sample((1000, 1000))

print 'Simple Convert'
%timeit SimpleDecode(SimpleEncode(arr))
print 'Base64 Encoding'
%timeit Base64Decode(Base64Encode(arr))

结果:

Simple Convert
1 loops, best of 3: 1.42 s per loop
Base64 Encoding
10 loops, best of 3: 171 ms per loop

这段代码对我很有用,但在序列化时需要进行解码: return json.dumps([str(ndarray.dtype),base64.b64encode(ndarray).decode('utf-8'),ndarray.shape])在反序列化时需要将其转换为字节数组: arr = np.frombuffer(base64.decodestring(bytearray(loaded[1], 'utf-8')), dtype) - johnbt
同时,要能够对数组进行base64编码,它需要在内存中是连续的,所以如果不是连续的,就需要进行转换: ndarr = np.ascontiguousarray(ndarray, dtype=ndarray.dtype) - johnbt

1

关于JSON可序列化部分,不太确定,但您可以先将其转换为字典?这似乎是JSON输出的更自然格式,并且可以处理任何数据类型的问题。

my_dict = dict(zip(my_array[1], my_array[0]))


这会保留我在数组中的顺序吗?(即,行my_array[0,0]: my_array[0,1]应该在行my_array[1,0]: my_array[1,1]之前打印,依此类推。) - Amelio Vazquez-Reina
但是字典保留它们的键值未排序。当我将其传递给JSON时,如何确保我的字典条目以正确顺序打印出来? - Amelio Vazquez-Reina
可能不行,所以也许这个方法行不通。Python字典默认是无序的。我认为Python 2.7有一个OrderedDict类,但是否可行取决于你的JSON库是否会尊重顺序。(刚注意到你回复了我之前的评论,但我已经删除了那条评论。我在仔细阅读评论之前回答了它。我还是比较新的,抱歉。) - Adam R. Nelson

0

如果所有的值都是数字,如果其他方法都失败了,你总可以手动完成它:

my_array = [['0.4', '0.7', '0.83', '0.3', '0.62', '0.51'],
            ['foo', 'bar', 'something', 'more']]

pairs = zip(my_array[1], my_array[0])
json_values = ('"{}": {}'.format(label, value) for label, value in pairs)
my_string = '{' + ', '.join(json_values) + '}'

print my_string # '{"foo": 0.4, "bar": 0.7, "something": 0.83, "more": 0.3}'

0
如果你只是想要一个漂亮的字符串表示你的数组,并且使用字符串数组类型不能给你想要的表示,那么消息序列化格式不是你要使用的东西。序列化格式用于保存/传输数据。Json很好,因为它通常也是可读的,但这不是它的目的,强制将其转换为其他格式将使其不再是json序列化。即使是savetxt和loadtxt numpy选项也无法满足你想要的格式(对每列重复第一行)。如果必须以该格式进行自定义序列化,可以使用以下代码:
def prettySerialize(inArray):
    ids = inArray[0]
    strRep = ''

    for row in inArray[1:]:
        for i,item in enumerate(row):
            rowStr = id[i] + ':' + item + '\n'
            strRep += rowStr

    return strRep
问题在于这样做会慢得多,数组的表示会更大(一遍又一遍地重复“id”行)。我强烈建议除非你专门为人类阅读格式化,否则采用纯json(或msgpack)解决方案...

这是我使用 msgpack 进行序列化的解决方案(也适用于 json)...将其转换为一个包括 dtype 和数组形状的元组:

def arrayToTuple(arr):
    if arr is None:
        return None

    return (arr.dtype.str, arr.shape, arr.tostring())

def arrayFromTuple(tupl):
    if tupl is None:
        return None

    typeStr, shape, dataStr = tupl

    resultArray = numpy.fromstring(dataStr, dtype=typeStr).reshape(shape)

    return resultArray

因此,转储和加载命令将是:

strRep = json.dumps(arrayToTuple(arr))
arrayFromTuple(json.loads(strRep))

对于msgpack.dumps和msgpack.loads(更快,更紧凑的二进制表示),这也适用。

一个可能适用于您的数组的警告:如果您的numpy数组是对象dtype,则它将不会通过标准方法序列化为完整数组。您必须单独序列化每个对象,因为存储在数组中的是对象id而不是数据。使用dtype='|S'作为最大字符串长度的dtype将使数组可序列化。


-1

asarray() 的输出是 numpy.ndarray 类型,旨在将列表/元组转换为 ndarrays。 - johnbt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,