代码之家  ›  专栏  ›  技术社区  ›  ascripter

圆形浮动值到间隔限制/网格

  •  9
  • ascripter  · 技术社区  · 8 年前

    我有一个(随机)浮点数数组。我想将每个值四舍五入到任意网格的极限。请参见以下示例:

    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的数组魔法。

    5 回复  |  直到 8 年前
        1
  •  9
  •   akuiper    8 年前

    如果 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' 返回此类间隔的最小索引,结果将落在 左开右关 脚本。

        2
  •  4
  •   andrew_reece    8 年前

    你可以用熊猫 cut() :

    import pandas as pd
    
    pd.cut(sample, intervals, labels=intervals[1:]).tolist()
    
        3
  •  1
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    另一个选择是:

    np.array(intervals)[(sample[:,None] > intervals).sum(axis=1)]
    #array([30., 18., 18., 15., 30., 10., inf, 18., 25., 21.])
    

    本质上,我们构建了一个检查样本是否大于间隔的掩码(假设它已经按照您的示例进行了排序)。然后,我们沿着第一个轴求和,这将为该值大于的每个间隔加上1。

    合成和是 intervals 数组。

    使用列表理解的非麻木解决方案(显然包括 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]
    
        4
  •  0
  •   Learning is a mess    8 年前

    没有运行检查,但:

     from bisect import bisect
    
     for index, value in enumerate(sample):
         sample[index] = intervals[ bisect( intervals, value)]
    
        5
  •  0
  •   blue_note    8 年前

    如果 values 是一个有你的值的1d数组,你可以做

    diff = values < intervals[:, None]
    t = np.argmax(diff, axis=0)
    new_values = intervals[t]