【问题标题】:How to read NumPy 2D array from string?如何从字符串中读取 NumPy 二维数组?
【发布时间】:2016-06-07 08:06:46
【问题描述】:

如何从字符串中读取 Numpy 数组?取一个字符串,如:

"[[ 0.5544  0.4456], [ 0.8811  0.1189]]"

并将其转换为数组:

a = from_string("[[ 0.5544  0.4456], [ 0.8811  0.1189]]")

a 成为对象的位置:np.array([[0.5544, 0.4456], [0.8811, 0.1189]])

我正在寻找一个非常简单的界面。将 2D 数组(浮点数)转换为字符串,然后将它们读回以重建数组的方法:

arr_to_string(array([[0.5544, 0.4456], [0.8811, 0.1189]])) 应该返回 "[[ 0.5544 0.4456], [ 0.8811 0.1189]]"

string_to_arr("[[ 0.5544 0.4456], [ 0.8811 0.1189]]") 应该返回对象array([[0.5544, 0.4456], [0.8811, 0.1189]])

理想情况下,arr_to_string 应该有一个精度参数来控制浮点转换为字符串的精度,这样您就不会得到像 0.4444444999999999999999999 这样的条目。

我在 NumPy 文档中找不到可以同时做到这一点的任何内容。 np.save 允许您创建一个字符串,但无法将其重新加载(np.load 仅适用于文件)。

【问题讨论】:

  • json.loadsjson.dumps 可能有用
  • 我收回了,我没有看到数组中缺少的逗号...
  • 我基本上是在寻找 np.array_str (docs.scipy.org/doc/numpy-1.10.1/reference/generated/…) 的倒数,但我找不到它
  • 您是否可以保存形状并仅保存展平的数组?因为如果你能做到这一点,你就可以轻松地使用现有的方法。当你准备好重组时,只需重塑它。另外,您是否将数组发送到字符串以进行序列化?它必须是人类可读的吗?
  • 你试过pickle吗?

标签: python numpy


【解决方案1】:

如果您的内部列表中的数字之间没有逗号,我不确定是否有一种简单的方法可以做到这一点,但如果有,那么您可以使用ast.literal_eval

import ast
import numpy as np
s = '[[ 0.5544,  0.4456], [ 0.8811,  0.1189]]'
np.array(ast.literal_eval(s))

array([[ 0.5544,  0.4456],
       [ 0.8811,  0.1189]])

编辑:我没有对它进行太多测试,但您可以使用 re 在需要的地方插入逗号:

import re
s1 = '[[ 0.5544  0.4456], [ 0.8811 -0.1189]]'
# Replace spaces between numbers with commas:
s2 = re.sub('(\d) +(-|\d)', r'\1,\2', s1)
s2
'[[ 0.5544,0.4456], [ 0.8811,-0.1189]]'

然后交给ast.literal_eval

np.array(ast.literal_eval(s2))
array([[ 0.5544,  0.4456],
       [ 0.8811, -0.1189]])

(您需要小心匹配数字之间的空格,以及数字和减号之间的空格)。

【讨论】:

  • 数字之间没有逗号,只有空格
  • @mvd 你可以试试我的编辑,但我还没有彻底测试过。
【解决方案2】:

挑战在于不仅要保存数据缓冲区,还要保存形状和数据类型。 np.fromstring 读取数据缓冲区,但作为一维数组;您必须从其他地方获取 dtype 和 shape。

In [184]: a=np.arange(12).reshape(3,4)

In [185]: np.fromstring(a.tostring(),int)
Out[185]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [186]: np.fromstring(a.tostring(),a.dtype).reshape(a.shape)
Out[186]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

保存 Python 对象的久负盛名的机制是pickle,而numpy 与pickle 兼容:

In [169]: import pickle

In [170]: a=np.arange(12).reshape(3,4)

In [171]: s=pickle.dumps(a*2)

In [172]: s
Out[172]: "cnumpy.core.multiarray\n_reconstruct\np0\n(cnumpy\nndarray\np1\n(I0\ntp2\nS'b'\np3\ntp4\nRp5\n(I1\n(I3\nI4\ntp6\ncnumpy\ndtype\np7\n(S'i4'\np8\nI0\nI1\ntp9\nRp10\n(I3\nS'<'\np11\nNNNI-1\nI-1\nI0\ntp12\nbI00\nS'\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x06\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\n\\x00\\x00\\x00\\x0c\\x00\\x00\\x00\\x0e\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x12\\x00\\x00\\x00\\x14\\x00\\x00\\x00\\x16\\x00\\x00\\x00'\np13\ntp14\nb."

In [173]: pickle.loads(s)
Out[173]: 
array([[ 0,  2,  4,  6],
       [ 8, 10, 12, 14],
       [16, 18, 20, 22]])

有一个numpy函数可以读取pickle字符串:

In [181]: np.loads(s)
Out[181]: 
array([[ 0,  2,  4,  6],
       [ 8, 10, 12, 14],
       [16, 18, 20, 22]])

您在字符串中提到了np.save,但您不能使用np.load。一种解决方法是进一步深入代码,并使用np.lib.npyio.format

In [174]: import StringIO

In [175]: S=StringIO.StringIO()  # a file like string buffer

In [176]: np.lib.npyio.format.write_array(S,a*3.3)

In [177]: S.seek(0)   # rewind the string

In [178]: np.lib.npyio.format.read_array(S)
Out[178]: 
array([[  0. ,   3.3,   6.6,   9.9],
       [ 13.2,  16.5,  19.8,  23.1],
       [ 26.4,  29.7,  33. ,  36.3]])

save 字符串有一个带有dtypeshape 信息的标题:

In [179]: S.seek(0)

In [180]: S.readlines()
Out[180]: 
["\x93NUMPY\x01\x00F\x00{'descr': '<f8', 'fortran_order': False, 'shape': (3, 4), }          \n",
 '\x00\x00\x00\x00\x00\x00\x00\x00ffffff\n',
 '@ffffff\x1a@\xcc\xcc\xcc\xcc\xcc\xcc#@ffffff*@\x00\x00\x00\x00\x00\x800@\xcc\xcc\xcc\xcc\xcc\xcc3@\x99\x99\x99\x99\x99\x197@ffffff:@33333\xb3=@\x00\x00\x00\x00\x00\x80@@fffff&B@']

如果你想要一个人类可读的字符串,你可以试试json

In [196]: import json

In [197]: js=json.dumps(a.tolist())

In [198]: js
Out[198]: '[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]'

In [199]: np.array(json.loads(js))
Out[199]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

去/去数组的列表表示是json 最明显的用法。有人可能写过更精细的json 数组表示。

您也可以采用csv 格式路线 - 有很多关于读取/写入 csv 数组的问题。


'[[ 0.5544  0.4456], [ 0.8811  0.1189]]'

是用于此目的的不良字符串表示形式。它看起来很像数组的str(),但使用, 而不是\n。但是没有一个干净的方法来解析嵌套的[],而且缺少分隔符是一种痛苦。如果它始终使用,,那么json 可以将其转换为列表。

np.matrix 接受类似 MATLAB 的字符串:

In [207]: np.matrix(' 0.5544,  0.4456;0.8811,  0.1189')
Out[207]: 
matrix([[ 0.5544,  0.4456],
        [ 0.8811,  0.1189]])

In [208]: str(np.matrix(' 0.5544,  0.4456;0.8811,  0.1189'))
Out[208]: '[[ 0.5544  0.4456]\n [ 0.8811  0.1189]]'

【讨论】:

  • 多么复杂而完整的答案!泡菜是这里的最佳选择。我还需要通过 AMQP 传输相当大的 2dim 浮点数组,而 pickle 完成了这项工作(即使没有 json)。非常感谢!
【解决方案3】:

转发到字符串:

import numpy as np
def array2str(arr, precision=None):
    s=np.array_str(arr, precision=precision)
    return s.replace('\n', ',')

返回数组:

import re
import ast
import numpy as np
def str2array(s):
    # Remove space after [
    s=re.sub('\[ +', '[', s.strip())
    # Replace commas and spaces
    s=re.sub('[,\s]+', ', ', s)
    return np.array(ast.literal_eval(s))

如果您使用repr() 将数组转换为字符串,则转换将是微不足道的。

【讨论】:

  • 这个答案很好用,因为它可以与 configparser 一起使用;这意味着 cmets 可以在文本文件中。见:stackoverflow.com/questions/30691797/…
  • [,\s]+ 中的[,\s]+ 中的strarray 不仅替换了空格,还替换了空格——所以如果你的数组是[1 2]\n[3 4],那么它也适用于这种情况.
【解决方案4】:

numpy.fromstring() 允许您轻松地从字符串创建一维数组。这是一个从字符串创建 2D numpy 数组的简单函数:

import numpy as np

def str2np(strArray):

    lItems = []
    width = None
    for line in strArray.split("\n"):
        lParts = line.split()
        n = len(lParts)
        if n==0:
            continue
        if width is None:
            width = n
        else:
            assert n == width, "invalid array spec"
        lItems.append([float(str) for str in lParts])
    return np.array(lItems)

用法:

X = str2np("""
    -2  2
    -1  3
     0  1
     1  1
     2 -1
     """)
print(f"X = {X}")

输出:

X = [[-2.  2.]
 [-1.  3.]
 [ 0.  1.]
 [ 1.  1.]
 [ 2. -1.]]

【讨论】:

    猜你喜欢
    • 2020-04-24
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    • 2020-07-12
    相关资源
    最近更新 更多