我正在努力将一些旧的文本日志转换为Python中的可用格式。
文件很大,所以我正在编写自己的C扩展,以尽快运行文件,并用正则表达式解析相关字段。我的最终目标是将这些字段导出到NumPy
strings
数组中。我知道可以在C中将NumPy
数组创建为PyObject
,然后在每个元素上调用SetItem
,但我希望尽可能地优化它。
我可以使用memcpy
或PyBuffer_FromMemory
之类的内容直接将C字符串读入NumPy
string
数组吗?我明白{ {1}}数组在内部类似于C数组,但我是否必须确保NumPy
数组将被连续分配?
我打算使用NumPy
数组来构建列NumPy
以进行统计分析。据我了解,Pandas
使用Pandas
数组来存储NumPy
中的列,因此从DataFrame
到NumPy
的开销不会很大。如果可能,我想避免Pandas
。
答案 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。例如,如果您将None
或nan
放入列中,则可能会将其更改为对象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))。
=================
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')
无需复制缓冲区即可正常工作。
但是,如果内存的不同部分是多个字符串,那么从它们构建数组将需要复制到连续的缓冲区。