有什么优雅的方法可以用 dtype 数组的列定义数据框吗?
Is there any elegant way to define a dataframe with column of dtype array?
我想处理pandas中的股票二级数据。为简单起见,假设每行有四种数据:
- 毫秒:时间戳,int64
- last_price: 最新成交价, float64,
- ask_queue:询问方成交量,固定大小(200)的int32数组
- bid_queue:出价方成交量,一个固定大小(200)的int32数组
这可以很容易地定义为 numpy 中的结构化数据类型:
dtype = np.dtype([
('millis', 'int64'),
('last_price', 'float64'),
('ask_queue', ('int32', 200)),
('bid_queue', ('int32', 200))
])
这样,我就可以像这样访问 ask_queue
和 bid_queue
:
In [17]: data = np.random.randint(0, 100, 1616 * 5).view(dtype)
% compute the average of ask_queue level 5 ~ 10
In [18]: data['ask_queue'][:, 5:10].mean(axis=1)
Out[18]:
array([33.2, 51. , 54.6, 53.4, 15. , 37.8, 29.6, 58.6, 32.2, 51.6, 34.4,
43.2, 58.4, 26.8, 54. , 59.4, 58.8, 38.8, 35.2, 71.2])
我的问题是如何定义一个DataFrame
包含数据?
这里有两种解决方案:
一个。将 ask_queue
和 bid_queue
设置为两列,数组值如下:
In [5]: df = pd.DataFrame(data.tolist(), columns=data.dtype.names)
In [6]: df.dtypes
Out[6]:
millis int64
last_price float64
ask_queue object
bid_queue object
dtype: object
但是,这个解决方案至少存在两个问题:
ask_queue
和 bid_queue
丢失了二维数组的 dtype 和所有
方便的方法;
- 性能,因为它变成了对象数组而不是 2D
数组。
乙。将 ask_queue
和 bid_quene
展平为 2 * 200
列:
In [8]: ntype = np.dtype([('millis', 'int64'), ('last_price', 'float64')] +
...: [(f'{name}{i}', 'int32') for name in ['ask', 'bid'] for i in range(200)])
In [9]: df = pd.DataFrame.from_records(data.view(ntype))
In [10]: df.dtypes
Out[10]:
millis int64
last_price float64
ask0 int32
ask1 int32
ask2 int32
ask3 int32
ask4 int32
ask5 int32
...
比解决方案 A 好。但是 2 * 200 列看起来多余。
有什么解决方案可以利用numpy中的结构化dtype吗?
我想知道 ExtensionArray
或 `ExtensionDtype' 是否可以解决这个问题。
Pandas 旨在处理和处理二维数据(您将放入电子表格中的那种)。因为 "ask_queue" 和 "bid_queue" 不是一维序列而是二维数组,所以你不能(轻易地)将它们推入 Pandas 数据框。
在这种情况下,您必须使用其他库,例如 xarray:http://xarray.pydata.org/
import xarray as xr
# Creating variables, first argument is the name of the dimensions
last_price = xr.Variable("millis", data["last_price"])
ask_queue = xr.Variable(("millis", "levels"), data["ask_queue"])
bid_queue = xr.Variable(("millis", "levels"), data["bid_queue"])
# Putting the variables in a dataset, the multidimensional equivalent of a Pandas
# dataframe
ds = xr.Dataset({"last_price": last_price, "ask_queue": ask_queue,
"bid_queue": bid_queue}, coords={"millis": data["millis"]})
# Computing the average of ask_queue level 5~10
ds["ask_queue"][{"levels": slice(5,10)}].mean(axis=1)
Q : Is there any solution can take the advantage as the structured dtype
in numpy
?
使用 L2-DoM 数据与仅 ToB(账簿顶部)喂价数据相比具有双重复杂性。 a) 本机提要速度很快(非常快/FIX 协议或其他私人数据提要提供成百上千的记录(在专业的基本事件期间更多)L2-DoM每毫秒变化。处理和存储都必须以性能为导向 b) 由于项目 a) 的性质,任何类型的离线分析都必须成功地操作并有效地处理大型数据集
- 存储 首选项
- 使用类似
numpy
的语法首选项
- 性能 偏好
存储首选项:已解决
鉴于 pandas.DataFrame
被设置为首选存储类型,让我们尊重这一点,即使语法和性能偏好可能会产生不利影响。
采用其他方式是可能的,但可能会引入未知的重构/重新设计成本,O/P 的操作环境不需要或已经不愿意承担。
话虽如此,pandas
必须将功能限制纳入设计考虑因素,所有其他步骤都必须接受,除非此偏好可能在未来某个时间得到修改。
numpy
-类似语法:已解决
这个要求是合理而明确的,因为 numpy
工具是为高性能数字 c运行ching 设计的快速而智能的工具。鉴于设置的存储偏好,我们将实施一对 numpy
-tricks 以便以合理的成本适应 pandas
2D-DataFrame
.STORE
和 .RETRIEVE
方向:
# on .STORE:
testDF['ask_DoM'][aRowIDX] = ask200.dumps() # type(ask200) <class 'numpy.ndarray'>
# on .RETRIEVE:
L2_ASK = np.loads( testDF['ask_DoM'][aRowIDX] ) # type(L2_ASK) <class 'numpy.ndarray'>
性能偏好:已测试
针对 .STORE
和 .RETRIEVE
方向的建议解决方案的净附加成本经测试采用:
.STORE
方向的一次性成本不少于70 [us]
且不超过~ 160 [us]
每个单元格对于 L2_DoM 数组的给定比例(平均:78 [ms]
StDev:9-11 [ms]
):
>>> [ f( [testDUMPs() for _ in range(1000)] ) for f in (np.min,np.mean,np.std,np.max) ]
[72, 79.284, 11.004153942943548, 150]
[72, 78.048, 10.546135548152224, 160]
[71, 78.584, 9.887971227708949, 139]
[72, 76.9, 8.827332496286745, 132]
在.RETRIEVE
方向上的重复成本不小于46 [us]
且不大于~ 123 [us]
每个单元格对于 L2_DoM 数组的给定比例(平均:50 [us]
StDev:9.5 [us]
):
>>> [ f( [testLOADs() for _ in range(1000)] ) for f in (np.min,np.mean,np.std,np.max) ]
[46, 50.337, 9.655194197943405, 104]
[46, 49.649, 9.462272665697178, 123]
[46, 49.513, 9.504293766503643, 123]
[46, 49.77, 8.367165350344164, 114]
[46, 51.355, 6.162434583831296, 89]
如果使用更好的架构对齐 int64
数据类型,则可以预期更高的性能(是的,以双倍的存储成本为代价,但计算成本将决定此举措是否具有性能优势) 并且有机会使用基于 memoryview
的操作,这可以减少喉咙并 将附加延迟减少到大约 22 [us]
.
测试在 py3.5.6、numpy v1.15.2 下 运行,使用:
>>> import numpy as np; ask200 = np.arange( 200, dtype = np.int32 ); s = ask200.dumps()
>>> from zmq import Stopwatch; aClk = Stopwatch()
>>> def testDUMPs():
... aClk.start()
... s = ask200.dumps()
... return aClk.stop()
...
>>> def testLOADs():
... aClk.start()
... a = np.loads( s )
... return aClk.stop()
...
平台 CPU、缓存层次结构和 RAM 详细信息:
>>> get_numexpr_cpuinfo_details_on_CPU()
'TLB size'______________________________:'1536 4K pages'
'address sizes'_________________________:'48 bits physical, 48 bits virtual'
'apicid'________________________________:'17'
'bogomips'______________________________:'7199.92'
'bugs'__________________________________:'fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2'
'cache size'____________________________:'2048 KB'
'cache_alignment'_______________________:'64'
'clflush size'__________________________:'64'
'core id'_______________________________:'1'
'cpu MHz'_______________________________:'1400.000'
'cpu cores'_____________________________:'2'
'cpu family'____________________________:'21'
'cpuid level'___________________________:'13'
'flags'_________________________________:'fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc extd_apicid aperfmperf eagerfpu pni pclmulqdq monitor ssse3 cx16 sse4_1 sse4_2 popcnt aes xsave avx lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 nodeid_msr topoext perfctr_core perfctr_nb cpb hw_pstate vmmcall arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold'
'fpu'___________________________________:'yes'
'fpu_exception'_________________________:'yes'
'initial apicid'________________________:'1'
'microcode'_____________________________:'0x6000626'
'model'_________________________________:'1'
'model name'____________________________:'AMD FX(tm)-4100 Quad-Core Processor'
'physical id'___________________________:'0'
'power management'______________________:'ts ttp tm 100mhzsteps hwpstate cpb'
'processor'_____________________________:'1'
'siblings'______________________________:'4'
'stepping'______________________________:'2'
'vendor_id'_____________________________:'AuthenticAMD'
'wp'____________________________________:'yes'
我想处理pandas中的股票二级数据。为简单起见,假设每行有四种数据:
- 毫秒:时间戳,int64
- last_price: 最新成交价, float64,
- ask_queue:询问方成交量,固定大小(200)的int32数组
- bid_queue:出价方成交量,一个固定大小(200)的int32数组
这可以很容易地定义为 numpy 中的结构化数据类型:
dtype = np.dtype([
('millis', 'int64'),
('last_price', 'float64'),
('ask_queue', ('int32', 200)),
('bid_queue', ('int32', 200))
])
这样,我就可以像这样访问 ask_queue
和 bid_queue
:
In [17]: data = np.random.randint(0, 100, 1616 * 5).view(dtype)
% compute the average of ask_queue level 5 ~ 10
In [18]: data['ask_queue'][:, 5:10].mean(axis=1)
Out[18]:
array([33.2, 51. , 54.6, 53.4, 15. , 37.8, 29.6, 58.6, 32.2, 51.6, 34.4,
43.2, 58.4, 26.8, 54. , 59.4, 58.8, 38.8, 35.2, 71.2])
我的问题是如何定义一个DataFrame
包含数据?
这里有两种解决方案:
一个。将 ask_queue
和 bid_queue
设置为两列,数组值如下:
In [5]: df = pd.DataFrame(data.tolist(), columns=data.dtype.names)
In [6]: df.dtypes
Out[6]:
millis int64
last_price float64
ask_queue object
bid_queue object
dtype: object
但是,这个解决方案至少存在两个问题:
ask_queue
和bid_queue
丢失了二维数组的 dtype 和所有 方便的方法;- 性能,因为它变成了对象数组而不是 2D 数组。
乙。将 ask_queue
和 bid_quene
展平为 2 * 200
列:
In [8]: ntype = np.dtype([('millis', 'int64'), ('last_price', 'float64')] +
...: [(f'{name}{i}', 'int32') for name in ['ask', 'bid'] for i in range(200)])
In [9]: df = pd.DataFrame.from_records(data.view(ntype))
In [10]: df.dtypes
Out[10]:
millis int64
last_price float64
ask0 int32
ask1 int32
ask2 int32
ask3 int32
ask4 int32
ask5 int32
...
比解决方案 A 好。但是 2 * 200 列看起来多余。
有什么解决方案可以利用numpy中的结构化dtype吗?
我想知道 ExtensionArray
或 `ExtensionDtype' 是否可以解决这个问题。
Pandas 旨在处理和处理二维数据(您将放入电子表格中的那种)。因为 "ask_queue" 和 "bid_queue" 不是一维序列而是二维数组,所以你不能(轻易地)将它们推入 Pandas 数据框。
在这种情况下,您必须使用其他库,例如 xarray:http://xarray.pydata.org/
import xarray as xr
# Creating variables, first argument is the name of the dimensions
last_price = xr.Variable("millis", data["last_price"])
ask_queue = xr.Variable(("millis", "levels"), data["ask_queue"])
bid_queue = xr.Variable(("millis", "levels"), data["bid_queue"])
# Putting the variables in a dataset, the multidimensional equivalent of a Pandas
# dataframe
ds = xr.Dataset({"last_price": last_price, "ask_queue": ask_queue,
"bid_queue": bid_queue}, coords={"millis": data["millis"]})
# Computing the average of ask_queue level 5~10
ds["ask_queue"][{"levels": slice(5,10)}].mean(axis=1)
Q : Is there any solution can take the advantage as the structured
dtype
innumpy
?
使用 L2-DoM 数据与仅 ToB(账簿顶部)喂价数据相比具有双重复杂性。 a) 本机提要速度很快(非常快/FIX 协议或其他私人数据提要提供成百上千的记录(在专业的基本事件期间更多)L2-DoM每毫秒变化。处理和存储都必须以性能为导向 b) 由于项目 a) 的性质,任何类型的离线分析都必须成功地操作并有效地处理大型数据集
- 存储 首选项
- 使用类似
numpy
的语法首选项 - 性能 偏好
存储首选项:已解决
鉴于 pandas.DataFrame
被设置为首选存储类型,让我们尊重这一点,即使语法和性能偏好可能会产生不利影响。
采用其他方式是可能的,但可能会引入未知的重构/重新设计成本,O/P 的操作环境不需要或已经不愿意承担。
话虽如此,pandas
必须将功能限制纳入设计考虑因素,所有其他步骤都必须接受,除非此偏好可能在未来某个时间得到修改。
numpy
-类似语法:已解决
这个要求是合理而明确的,因为 numpy
工具是为高性能数字 c运行ching 设计的快速而智能的工具。鉴于设置的存储偏好,我们将实施一对 numpy
-tricks 以便以合理的成本适应 pandas
2D-DataFrame
.STORE
和 .RETRIEVE
方向:
# on .STORE:
testDF['ask_DoM'][aRowIDX] = ask200.dumps() # type(ask200) <class 'numpy.ndarray'>
# on .RETRIEVE:
L2_ASK = np.loads( testDF['ask_DoM'][aRowIDX] ) # type(L2_ASK) <class 'numpy.ndarray'>
性能偏好:已测试
针对 .STORE
和 .RETRIEVE
方向的建议解决方案的净附加成本经测试采用:
.STORE
方向的一次性成本不少于70 [us]
且不超过~ 160 [us]
每个单元格对于 L2_DoM 数组的给定比例(平均:78 [ms]
StDev:9-11 [ms]
):
>>> [ f( [testDUMPs() for _ in range(1000)] ) for f in (np.min,np.mean,np.std,np.max) ]
[72, 79.284, 11.004153942943548, 150]
[72, 78.048, 10.546135548152224, 160]
[71, 78.584, 9.887971227708949, 139]
[72, 76.9, 8.827332496286745, 132]
在.RETRIEVE
方向上的重复成本不小于46 [us]
且不大于~ 123 [us]
每个单元格对于 L2_DoM 数组的给定比例(平均:50 [us]
StDev:9.5 [us]
):
>>> [ f( [testLOADs() for _ in range(1000)] ) for f in (np.min,np.mean,np.std,np.max) ]
[46, 50.337, 9.655194197943405, 104]
[46, 49.649, 9.462272665697178, 123]
[46, 49.513, 9.504293766503643, 123]
[46, 49.77, 8.367165350344164, 114]
[46, 51.355, 6.162434583831296, 89]
如果使用更好的架构对齐 int64
数据类型,则可以预期更高的性能(是的,以双倍的存储成本为代价,但计算成本将决定此举措是否具有性能优势) 并且有机会使用基于 memoryview
的操作,这可以减少喉咙并 将附加延迟减少到大约 22 [us]
.
测试在 py3.5.6、numpy v1.15.2 下 运行,使用:
>>> import numpy as np; ask200 = np.arange( 200, dtype = np.int32 ); s = ask200.dumps()
>>> from zmq import Stopwatch; aClk = Stopwatch()
>>> def testDUMPs():
... aClk.start()
... s = ask200.dumps()
... return aClk.stop()
...
>>> def testLOADs():
... aClk.start()
... a = np.loads( s )
... return aClk.stop()
...
平台 CPU、缓存层次结构和 RAM 详细信息:
>>> get_numexpr_cpuinfo_details_on_CPU()
'TLB size'______________________________:'1536 4K pages'
'address sizes'_________________________:'48 bits physical, 48 bits virtual'
'apicid'________________________________:'17'
'bogomips'______________________________:'7199.92'
'bugs'__________________________________:'fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2'
'cache size'____________________________:'2048 KB'
'cache_alignment'_______________________:'64'
'clflush size'__________________________:'64'
'core id'_______________________________:'1'
'cpu MHz'_______________________________:'1400.000'
'cpu cores'_____________________________:'2'
'cpu family'____________________________:'21'
'cpuid level'___________________________:'13'
'flags'_________________________________:'fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc extd_apicid aperfmperf eagerfpu pni pclmulqdq monitor ssse3 cx16 sse4_1 sse4_2 popcnt aes xsave avx lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 nodeid_msr topoext perfctr_core perfctr_nb cpb hw_pstate vmmcall arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold'
'fpu'___________________________________:'yes'
'fpu_exception'_________________________:'yes'
'initial apicid'________________________:'1'
'microcode'_____________________________:'0x6000626'
'model'_________________________________:'1'
'model name'____________________________:'AMD FX(tm)-4100 Quad-Core Processor'
'physical id'___________________________:'0'
'power management'______________________:'ts ttp tm 100mhzsteps hwpstate cpb'
'processor'_____________________________:'1'
'siblings'______________________________:'4'
'stepping'______________________________:'2'
'vendor_id'_____________________________:'AuthenticAMD'
'wp'____________________________________:'yes'