我正在努力将一些旧文本日志转换为 Python 中可用的格式。
文件很大,所以我正在编写自己的 C 扩展程序以尽快运行文件并使用正则表达式解析出相关字段。我的最终目标是将这些字段导出到 NumPy
的 strings
数组中。我知道可以在 C 中将 NumPy
数组创建为 PyObject
,然后在每个元素上调用 SetItem
,但我希望优化尽我所能。
我可以使用 memcpy
或 PyBuffer_FromMemory
之类的东西将 C 字符串读入 NumPy
string
直接数组?我知道 NumPy
数组在内部类似于 C 数组,但我是否必须确保 NumPy
数组将被连续分配?
我打算使用 NumPy
数组构建列 Pandas
以进行统计分析。据我了解,Pandas
使用 NumPy
数组将列存储在 DataFrame
中,因此我不会从 中获得大量开销NumPy
到 Pandas
。如果可能,我想避免使用 cython
。
最佳答案
为了让您了解字符串数组的存储方式,我将制作一个并以多种方式查看它:
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 的新数组。以及将数据 block 复制到这些数组的函数。查看 numpy 文档的 C
端,或查看其 github 存储库中的一些 numpy 代码。
关于 pandas
传输,请注意 pandas
很容易更改其列的数据类型。例如,如果您将 None
或 nan
放在列中,它可能会将其更改为对象数据类型。
对象数组在数据缓冲区中存储指针。
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 个 4 字节指针。这些字符串作为常规 Python 字符串存储在内存中的其他地方(在本例中为 unicode 字符串 (Py3))。
=================
fromstring
和 frombuffer
让我从缓冲区重新创建数组
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')
这在不复制缓冲区的情况下工作。
但是,如果内存的不同部分有多个字符串,则从它们构建数组将需要复制到连续缓冲区中。
关于python - 将 C 字符串公开给 NumPy 的最快方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39133578/