【问题标题】:How to build a string out of sparse array efficiently in python如何在python中有效地从稀疏数组中构建一个字符串
【发布时间】:2016-10-25 16:45:11
【问题描述】:

我在 python 中使用 scipy 处理稀疏数组/矩阵。

我有一个稀疏数组[由其他两个之间的点积生成]。这个数组的大小应该很大(可以是数百),但是这段代码会被多次调用。所以它一定很高效。

我需要一种有效的方法来创建一个 1 和 0 的字符串,如下所示:

    nonzeros = np.nonzero(hashcode)
    arr = ['0']*hashcode_length
    if nonzeros != None:
        for i in nonzeros[1]:
            arr[i] = '1'
    concatenated = ''.join(arr)

例如...如果稀疏数组的长度为 10 并且值为:

    [0, 0, 1, 1, 0, 1, 0, 0, 0, 1]

输出应该是:

    "0011010001"

如何改进这段代码?

注意

  • 抱歉没有放所有代码,因为它很大而且有太多 不相关的细节
  • 如果问题不清楚或有更多详细信息,请告诉我 需要

【问题讨论】:

  • 数组从何而来?你在用最后的字符串做什么?我问的原因是因为 python 程序的性能关键部分可以用 c/c++ 编写:在this page 的底部,它们显示了语言的比较。就个人经验而言,当我们将图形求解器从 python 重写为 c 时,我们经历了几个数量级的速度提高。 Python 花了大约 90 秒来解决一张图。在 C 语言中,由于巧妙地使用了位旋转,它在一秒钟内解决了我们所有的 1200 个图。
  • 您希望nonzeros 何时成为None
  • 数组无法计算和乘法 - 我正在使用 python 实现一些算法。您可以简单地假设给定数组并且它的值是 1 或 0(整数值)

标签: python arrays join scipy sparse-matrix


【解决方案1】:

我的第一个想法是这样的:

In [1380]: x=sparse.coo_matrix([0,0,1,1,0,1,0,0,0,1])
In [1381]: ''.join([str(i) for i in x.A.ravel().tolist()])
Out[1381]: '0011010001'

不一定更好,但我认为它说明了一些关键问题。使用稀疏矩阵或密集矩阵有用吗?如何将整数转换为字符串?这是 1 行矩阵吗?

我可以用astype改进字符串转换:

In [1393]: ''.join(x.A.ravel().astype('U1'))
Out[1393]: '0011010001'

join 正在对数组执行列表迭代。

对于字节串(PY3,或 PY2 中的普通字符串),tostringjoin 的替代品。这只是将数据缓冲区作为字符串返回:

In [1451]: x.A.astype('S1').tostring()
Out[1451]: b'0011010001'

我可以在稀疏矩阵上使用astype,但是有一个错误阻止我使之变得密集:

In [1397]: x.astype('U1').A
...
ValueError: unsupported data types in input

============================

迭代的变体;以0 字符串开头;列出清单; sparse.nonzero 只返回来自coo 格式矩阵的.col 值。

In [1403]: ll    # ll = '0'*x.shape[1]
Out[1403]: '0000000000'
In [1404]: ll=list(ll)
In [1405]: ll
Out[1405]: ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
In [1406]: for i in x.col:
      ...:     ll[i]='1'
      ...:     
In [1407]: ll
Out[1407]: ['0', '0', '1', '1', '0', '1', '0', '0', '0', '1']
In [1408]: ''.join(ll)
Out[1408]: '0011010001'

或者对字符串数组做同样的事情:

In [1416]: ll=np.empty(x.shape[1], dtype='U1')
In [1417]: ll.fill('0')
In [1418]: ll
Out[1418]: 
array(['0', '0', '0', '0', '0', '0', '0', '0', '0', '0'], 
      dtype='<U1')
In [1419]: ll[x.col]='1'
In [1420]: ll
Out[1420]: 
array(['0', '0', '1', '1', '0', '1', '0', '0', '0', '1'], 
      dtype='<U1')

这避免了循环,因为我可以一次分配多个值。

对于这个小例子,列表解决方案可能同样快或更快。数组版本有一些数组创建开销,所以如果情况很大,它们是最好的。

即使对于具有 (1,1210) 形状的 coo 矩阵,此列表迭代版本也明显更快:

def foo1(x):
    ll=list('0'*x.shape[1])   # ll=['0']*x.shape[1] is little faster
    for i in x.col:
        ll[i]='1'
    return ''.join(ll)

如果矩阵不是coo,则转换它,x.tocoo() 或使用x.nonzero()(但请查看其代码)。

=========

我忽略了您的 None 测试。为什么会在那里?可能很危险

In [1448]: x.nonzero()[1] != None
/usr/local/bin/ipython3:1: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.
  #!/usr/bin/python3
Out[1448]: True

【讨论】:

    猜你喜欢
    • 2015-02-18
    • 2011-12-16
    • 2012-05-18
    • 2011-01-23
    • 2020-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    相关资源
    最近更新 更多