从分隔的字符串

时间:2018-04-20 19:31:01

标签: python scipy sparse-matrix

我正在处理大量二进制数据,这些二进制数据逐行进入我的程序,看起来像\t\t1\t\t1\t\t\t(但更长)。可以想象,这些是来自制表符分隔文件的行。

显然,我可以'\t\t1\t\t1\t\t\t'.split('\t')获取1''的列表,我可以很容易地将其转换为1和0或T / F或其他任何内容。但是,数据非常稀疏(很多0并且不是很多1)所以我希望使用某种稀疏表示。

我的问题是:有没有人知道直接从这个字符串转到类似scipy.sparse.csr_matrix() 的方法,而不必首先创建一个中间密集矩阵?

我尝试将分割字符串(即1''的列表)直接传递给csr_matrix(),我得到TypeError: no supported conversion for types: (dtype('<U1'),)

正如我所说,我可以做上面的事情并获得1和0然后将那个转换为csr_matrix()然后我失去了稀疏的所有速度和内存优势因为无论如何我正在制作完全密集的版本。

2 个答案:

答案 0 :(得分:1)

scipy无法解释您的输入,因为它不知道您希望将空字符串转换为0.这样可以正常工作:

>>> from scipy.sparse import csr_matrix
>>> x = [0 if not a else int(a) for a in "\t\t\t\t1\t\t\t1\t\t\t".split('\t')] 
>>> csr_matrix(x)
<1x11 sparse matrix of type '<class 'numpy.int64'>'
        with 2 stored elements in Compressed Sparse Row format>

确保您的列表在矩阵化之前都是numbrt格式。

关注OP评论我回忆说你可以强制将空字符串转换为0,所以更好的解决方案将是

>>> csr_matrix("\t\t\t\t1\t\t\t1\t\t\t".split('\t'),dtype=np.int64)
<1x11 sparse matrix of type '<class 'numpy.int64'>'
        with 2 stored elements in Compressed Sparse Row format>

生成一个较少的列表。

答案 1 :(得分:0)

这是一种逐行处理数据的方法:

In [32]: astr = '\t\t1\t\t1\t\t\t'      # sample row
In [33]: row, col = [],[]
In [34]: for i in range(5):
    ...:     c = [j for j,v in enumerate(astr.split('\t')) if v]
    ...:     row.extend([i]*len(c))
    ...:     col.extend(c)
    ...: data = np.ones(len(col),'int32')
    ...: M = sparse.csr_matrix((data, (row, col)))
    ...: 
In [35]: M
Out[35]: 
<5x5 sparse matrix of type '<class 'numpy.int32'>'
    with 10 stored elements in Compressed Sparse Row format>
In [36]: M.A
Out[36]: 
array([[0, 0, 1, 0, 1],
       [0, 0, 1, 0, 1],
       [0, 0, 1, 0, 1],
       [0, 0, 1, 0, 1],
       [0, 0, 1, 0, 1]], dtype=int32)

对于每一行,我只收集&#39; 1的索引。从这些我构建相应的datarow列表(或数组)。从理论上讲,我可以构建indptr来创建更直接的csr,但coo样式更容易理解。

中间值是:

In [40]: c
Out[40]: [2, 4]
In [41]: row
Out[41]: [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
In [42]: col
Out[42]: [2, 4, 2, 4, 2, 4, 2, 4, 2, 4]
In [43]: data
Out[43]: array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int32)

获取c值的另一种方法是:

In [46]: np.where(astr.split('\t'))[0]
Out[46]: array([2, 4])

(但列表理解更快)。

字符串和列表find/index方法找到第一项,但不是全部。