我有一个(随机)浮点数数组。我想将每个值四舍五入到任意网格的限制。请参见以下示例:
import numpy as np
np.random.seed(1)
# Setup
sample = np.random.normal(loc=20, scale=6, size=10)
intervals = [-np.inf, 10, 12, 15, 18, 21, 25, 30, np.inf]
# Round each interval up
for i in range(len(intervals) - 1):
sample[np.logical_and(sample > intervals[i], sample <= intervals[i+1])] = intervals[i+1]
结果是:
[ 30. 18. 18. 15. 30. 10. inf 18. 25. 21.]
如何避免for
循环?我确定有某种方式可以使用NumPy的数组魔术,但现在还看不到。
答案 0 :(得分:9)
如果intervals
已排序,则可以使用np.searchsorted
:
np.array(intervals)[np.searchsorted(intervals, sample)]
# array([ 30., 18., 18., 15., 30., 10., inf, 18., 25., 21.])
searchsorted
返回元素所属间隔的索引:
np.searchsorted(intervals, sample)
# array([7, 4, 4, 3, 7, 1, 8, 4, 6, 5])
默认的side='left'
返回该间隔的最小索引,结果属于左打开,右关闭的情况。
答案 1 :(得分:4)
您可以使用熊猫cut()
:
import pandas as pd
pd.cut(sample, intervals, labels=intervals[1:]).tolist()
答案 2 :(得分:1)
另一个选择是:
np.array(intervals)[(sample[:,None] > intervals).sum(axis=1)]
#array([30., 18., 18., 15., 30., 10., inf, 18., 25., 21.])
本质上,我们构建了一个遮罩,以检查样本是否大于间隔(假设它已按照示例中的顺序进行了排序)。然后,我们沿第一个轴求和,对于每个大于该值的间隔,该轴将合计1。
结果总和是intervals
数组中的索引。
使用列表理解的非NumPy解决方案(显然包括for
循环,但对于生成器而言应该相对有效):
new_sample = [next(i for i in intervals if i>s) for s in sample]
#[30, 18, 18, 15, 30, 10, inf, 18, 25, 21]
答案 3 :(得分:0)
没有运行检查,但是:
from bisect import bisect
for index, value in enumerate(sample):
sample[index] = intervals[ bisect( intervals, value)]
答案 4 :(得分:0)
如果values
是具有您的值的一维数组,则可以执行类似的操作
diff = values < intervals[:, None]
t = np.argmax(diff, axis=0)
new_values = intervals[t]