我在python中创建一个函数,根据x数组将两个数组x和y分成预定数量的bin。我已经制作了一个可行的算法,但它确实很慢。这是(显然)有效的代码:
def sepbin(x, y, classes_number=100, log_scale=True):
if log_scale:
if x[0]<=0:
print 'Warning: zero value in array about to be log-scaled. Ignoring it.'
x=x[1:]
y=y[1:]
bins=np.logspace(np.log(x[0]), np.log(x[-1]), classes_number+1, base=np.e)
else:
bins=np.linspace(x[0], x[-1], classes_number+1)
ybins=[[] for i in range(classes_number)]
xbins=[[] for i in range(classes_number)]
for xx, yy in zip(x,y):
i=0
while i<classes_number:
if ((xx>=bins[i]) and (xx<bins[i+1])):
ybins[i].append(yy)
xbins[i].append(xx)
break
elif (i==(classes_number-1)) and xx==bins[-1]:
ybins[i].append(yy)
xbins[i].append(xx)
break
else:
i+=1
xsm = np.array(map(np.mean, xbins))
ysm = np.array(map(np.mean, ybins))
return xsm, ysm
正如您所看到的,我想为对数缩放和线性缩放的输出腾出空间,因此我不能假设线性间隔的分档。我只假设数据按新月或递减顺序排列(但这很容易概括)。
显然,代码运行良好,但由于我希望使用非常大的数据集(100000多个元素),我认为应该优化它。我有什么办法可以在这里使用numpy
或scipy
来加快速度吗?令我感到惊讶的是,我在numpy
中找不到分箱功能!所以也许我看起来不对。
谢谢。
答案 0 :(得分:0)
您可以使用numpy的索引来查找每个bin中x
和y
的元素,而不是您的O(nk)双循环:
def sepbin2(x, y, classes_number=100, log_scale=True):
if log_scale:
if x[0]<=0:
print 'Warning: zero value in array about to be log-scaled. Ignoring it.'
x=x[1:]
y=y[1:]
bins=np.logspace(np.log(x[0]), np.log(x[-1]), classes_number+1, base=np.e)
else:
bins=np.linspace(x[0], x[-1], classes_number+1)
# pre-allocate return values
xsm = np.zeros(classes_number)
ysm = np.zeros(classes_number)
# find elements in each bin
for i in range(classes_number):
if i == classes_number - 1:
sel = bins[i] <= x
else:
sel = (bins[i] <= x) & (x < bins[i+1])
xsm[i] = np.mean(x[sel])
ysm[i] = np.mean(y[sel])
return xsm, ysm
在我的测试中,这个函数似乎提供与你编写的输出完全相同的输出。我使用稍微不同的代码来选择最后一个bin(我不确定你为什么写xx==bins[-1]
)。
sepbin2
速度要快得多。使用100K数据点:
x = np.random.random((100000,))
x.sort()
y = np.random.random((100000,))
我们得到:
In [1]: %timeit sepbin(x, y, classes_number=100)
1 loops, best of 3: 5.21 s per loop
In [2]: %timeit sepbin2(x, y, classes_number=100)
100 loops, best of 3: 18.9 ms per loop