将C字符串暴露给NumPy的最快方法?

时间:2016-08-24 21:50:55

标签: python c arrays numpy cython

我正在努力将一些旧的文本日志转换为Python中的可用格式。 文件很大,所以我正在编写自己的C扩展,以尽快运行文件,并用正则表达式解析相关字段。我的最终目标是将这些字段导出到NumPy strings数组中。我知道可以在C中将NumPy数组创建为PyObject,然后在每个元素上调用SetItem,但我希望尽可能地优化它。

我可以使用memcpyPyBuffer_FromMemory之类的内容直接将C字符串读入NumPy string数组吗?我明白{ {1}}数组在内部类似于C数组,但我是否必须确保NumPy数组将被连续分配?

我打算使用NumPy数组来构建列NumPy以进行统计分析。据我了解,Pandas使用Pandas数组来存储NumPy中的列,因此从DataFrameNumPy的开销不会很大。如果可能,我想避免Pandas

1 个答案:

答案 0 :(得分:3)

为了理解如何存储字符串数组,我将制作一个字符串,并以多种方式查看它:

In [654]: np.array(['one','two','three','four'],dtype='S5')
Out[654]: 
array([b'one', b'two', b'three', b'four'], 
      dtype='|S5')
In [655]: x=np.array(['one','two','three','four'],dtype='S5')
In [656]: x.tostring()
Out[656]: b'one\x00\x00two\x00\x00threefour\x00'
In [657]: x.view(np.uint8)
Out[657]: 
array([111, 110, 101,   0,   0, 116, 119, 111,   0,   0, 116, 104, 114,
       101, 101, 102, 111, 117, 114,   0], dtype=uint8)

因此它的数据缓冲区由20个字节(4 * S5)组成。对于短于5的字符串,它会将0放入(或离开)字节中。

是的,有C函数可用于创建给定大小和dtype的新数组。以及将数据块复制到这些数组的功能。查看numpy文档的C侧,或者查看它的github存储库中的一些numpy代码。

关于pandas转移,请注意pandas可以随时更改其列的dtype。例如,如果您将Nonenan放入列中,则可能会将其更改为对象dtype。

对象数组在数据缓冲区中存储指针。

In [658]: y=np.array(['one','two','three','four'],dtype=object)
In [659]: y
Out[659]: array(['one', 'two', 'three', 'four'], dtype=object)
In [660]: y.tostring()
Out[660]: b'\xe0\x0f\xc5\xb5\xa0\xfah\xb5\x80\x0b\x8c\xb4\xc09\x8b\xb4'

如果我解释正确,数据缓冲区有16个字节--4个4byte指针。字符串作为常规Python字符串存储在内存中的其他位置(在本例中为unicode字符串(Py3))。

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

fromstringfrombuffer让我从缓冲区重新创建一个数组

In [696]: x=np.array(['one','two','three','four'],dtype='S5')
In [697]: xs=x.tostring()
In [698]: np.fromstring(xs,'S5')
Out[698]: 
array([b'one', b'two', b'three', b'four'], 
      dtype='|S5')
In [700]: np.frombuffer(xs,'S5')
Out[700]: 
array([b'one', b'two', b'three', b'four'], 
      dtype='|S5')

无需复制缓冲区即可正常工作。

但是,如果内存的不同部分是多个字符串,那么从它们构建数组将需要复制到连续的缓冲区。