说明
主要是利用numpy的广播进行高效的区间映射计算。在以前的函数上进行了修改,使得字符串也可以映射区间。
内容
先给结果
import numpy as np
# 输入一个数据序列(vector)和一个尺度序列(vector),返回数据映射的区间序列。按左闭右开原则。ruler两侧要加上极大极小的限制。
def np_interval_mapping(x_list, ruler_list):
# 都转换为numpy array
x1_dim1 = np.array(x_list)
# 尺度必须为有序的
r1_dim1 = np.sort(np.array(ruler_list))
# 将x升维
x1_dim2 = np.expand_dims(x1_dim1, -1)
# 区间映射
res_vec = len(r1_dim1) - (x1_dim2 < r1_dim1).sum(axis=1)
return res_vec
---
%%timeit
np_interval_mapping([1,2], [-1,0,1,2,3])
13.2 µs ± 279 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
np_interval_mapping(['a','b'], ['a','b','c','d','e'])
13.4 µs ± 452 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
总体来说速度是很快的,尤其在数据量大的时候。我记得numpy的广播有点像异步执行的机制,但是效率肯定比调用其他包要更高。(更不要说for循环了)
原理简单解释
#x = np.array([1])
x = np.array(['b'])
#qtiles = np.array([0,1,2,3])
qtiles = np.array(['a','b','c','d'])
a1 = np.expand_dims(x, -1)
array([['b']], dtype='<U1')
a1.shape
(1,1)
a1 < qtiles
array([[False, False, True, True]])
a2 = (len(qtiles1) + 1) - (a1 < qtiles1).sum(axis=1)
首先,将要处理的数据(向量)升维为矩阵。这样再相减就触发了广播(向量-向量)。
其次,每个向量对进行比较。由于尺子排过序,所以只要数据比尺子小的区间都是True。
最后,将尺子的总格子数减掉尺子刻度是True的和,就得到了数据的区间号。
所以,两次广播。一次计算尺子的刻度,一次计算区间。