如何在 python 中有效地从稀疏数组构建字符串

How to build a string out of sparse array efficiently in python

我在 python 中使用 scipy 用于稀疏 arrays/matrices。

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

我需要的是一种创建 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"

如何改进此代码?

注意

我的第一个想法是:

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 的替代方法。这只是 returns 作为字符串的数据缓冲区:

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

我可以在稀疏矩阵上使用 astype,但是有一个 bug 阻止我做那个密集:

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

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

迭代的变体;以 0 字符串开头;把它列成一个清单; sparse.nonzero 只是 returns 来自 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