【问题标题】:Numpy finding interval which has a least k points具有至少 k 个点的 Numpy 查找区间
【发布时间】:2020-10-02 10:13:17
【问题描述】:

我在[0,20]区间有一些点

我有一个大小为window_size=3 的窗口,我可以在上述区间内移动。因此,窗口的开头 - 让我们调用 start 被限制为 [0,17]

假设我们在下面有一些points

points = [1.4,1.8,   11.3,11.8,12.3,13.2,  18.2,18.3,18.4,18.5]

如果我们想要至少min_points=4 点,则窗口开始范围的解决方案(我手动找到的)是:

suitable_starts = [[10.2,11.3],[15.5,17.0]]

即大小3 窗口的开始可以从10.211.3 和从15.517.0简单地说,窗口的对应结束只是开始范围的+3

我正在寻找一种通过巧妙的numpyscipy 或其他功能在算法上快速解决此问题的方法。

我正在寻找的一般功能是:

get_start_windows(interval = [0,20],
    window_size = 3.0, 
    points = [1.4,1.8,11.3,11.8,12.3,13.2,18.2,18.3,18.4,18.5],
    min_points = 4

    return suitable_starts # suitable_starts = [[10.2,11.3],[15.5,17.0]]

注意:

正如 cmets 中的某个人所指出的,有时在某些特殊情况下,点之间的距离正好是 window_size。然而实际上这些点是双浮点数,它们不可能完全分开 window_size,因此可以忽略它们。

这些特殊的例子包括:

points = [1.4,1.8,  11.3,11.8,12.3,13.2,14.2,15.2,16.2,17.2,18.2,18.3,18.4,18.5]

但这些可以安全地忽略。

【问题讨论】:

  • 如果我在你身边,我会分享你的“手动”/“慢”方法,以便有一些东西可以比较
  • 恐怕我不完全理解你的逻辑,但间隔不应该是[10.2, 11.3](因为10.2 + 3.0 = 13.2)和[15.5, 17.0](因为15.5 + 3.0 = 18.5)!?
  • @HansHirse 你是对的。现在编辑。
  • 下一个问题:如何定义“间隔”?预期结果是什么:a) points = [1.4,1.8,2.8,3.8,4.8,11.3,11.8,12.3,13.2,18.2,18.3,18.4,18.5] 和 b) points = [1.4,1.8,11.3,11.8,12.3,13.2,14.2,15.2,16.2,17.2,18.2,18.3,18.4,18.5]
  • 我猜是 sn-p 代码的错字,你的意思是 min_points=4

标签: python numpy scipy


【解决方案1】:

经过一番挣扎,我想出了这个解决方案。

先解释一下,和思路:

  • 理想情况下,我们希望设置一个窗口大小并将其从最左边的可接受点滑动到最右边的可接受点,并在min_points 在窗口中时开始计数,并在min_points 不再在窗口内时结束计数它(把它想象成一个抽搐操作者左右)
  • 基本的陷阱是我们想要离散滑动,所以这里的技巧是只检查点的数量何时低于或高于min_points,这意味着每次出现元素或window_size它(正如optional_starts 反映的那样)
  • 然后迭代 optional_starts 并采样第一次满足条件,以及每个时间间隔满足条件的最后一个

所以按照上面的描述编写了以下代码:

def consist_at_least(start, points, min_points, window_size):
    a = [point for point in points if start <= point <= start + window_size]
    return len(a)>=min_points
    


points = [1.4,1.8,   11.3,11.8,12.3,13.2,  18.2,18.3,18.4,18.5]
min_points = 4
window_size = 3
total_interval = [0,20]
optional_starts = points + [item-window_size for item in points if item-window_size>=total_interval[0]] + [total_interval[0] + window_size] + [total_interval[1] - window_size] + [total_interval[0]]
optional_starts = [item for item in optional_starts if item<=total_interval[1]-window_size]
intervals = []
potential_ends = []
for start in sorted(optional_starts):
    is_start_interval = len(intervals)%2 == 0
    if consist_at_least(start, points, min_points, window_size):
        if is_start_interval:
            intervals.append(start)
        else:
            potential_ends.append(start)
    elif len(potential_ends)>0 :
        intervals.append(potential_ends[-1])
        potential_ends = []
if len(potential_ends)>0:
    intervals.append(potential_ends[-1])

print(intervals)

输出:

[10.2, 11.3, 15.5, 17]

每 2 个连续元素反映区间的开始和结束

【讨论】:

  • 谢谢尤西。不幸的是,我用points = [1.4,1.8,1.9,2.0,17.2,18.2,18.3,18.4,18.5] 交换了积分,得到了[1.4,17],这是不正确的。
  • 那是因为我出于某种原因排除了total_interval[0],现在编辑后它也适用于这个输入
  • 对于以下points= [1.4, 1.5,1.6,1.7,1.8,1.9,2.0,2.1, 3.49],我得到的答案[0.4900000000000002, 1.9] 不正确。正确的间隔应该是[0,1.9]
  • 也许您尝试在编辑之前运行之前的代码?因为我得到了你发现的正确答案 - [0,1.9]
  • 抱歉我的不好。
【解决方案2】:

因此,在提供有关“间隔”性质的其他信息后,我提出以下解决方案,假设间隔距离至少为window_size

import numpy as np


def get_start_windows(inter, ws, p, mp):

    # Initialize list of suitable start ranges
    start_ranges = []

    # Determine possible intervals w.r.t. to window size
    int_start = np.insert(np.array([0, p.shape[0]]), 1,
                          (np.argwhere(np.diff(p) > ws) + 1).squeeze()).tolist()

    # Iterate found intervals
    for i in np.arange(len(int_start)-1):

        # The actual interval
        int_ = p[int_start[i]:int_start[i+1]]

        # If interval has less than minimum points, reject
        if int_.shape[0] < mp:
            continue

        # Determine first and last possible starting point
        first = max(inter[0], int_[mp-1] - ws)
        last = min(int_[-mp], inter[1] - ws)

        # Add to list of suitable start ranges
        start_ranges.append((first, last))

    return start_ranges


# Example 1
interval = [0, 20]
window_size = 3.0
min_points = 4
points = [1.4, 1.8, 11.3, 11.8, 12.3, 13.2, 18.2, 18.3, 18.4, 18.5]
print(get_start_windows(interval, window_size, np.array(points), min_points))

# Example 2
points = [1.4, 1.8, 1.9, 2.1, 11.3, 11.8, 12.3, 13.2, 18.2, 18.3, 18.4, 18.5]
print(get_start_windows(interval, window_size, np.array(points), min_points))

# Example 3
points = [1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 3.49]
print(get_start_windows(interval, window_size, np.array(points), min_points))

(代码可能优化了,我没注意...)

输出:

[(10.2, 11.3), (15.5, 17.0)]
[(0, 1.4), (10.2, 11.3), (15.5, 17.0)]
[(0, 1.9)]

希望该解决方案涵盖所需的情况。

-------------------------------------
System information
-------------------------------------
Platform:   Windows-10-10.0.16299-SP0
Python:     3.8.5
NumPy:      1.19.2
-------------------------------------

【讨论】:

  • 对于下面的points= [1.4, 1.5,1.6,1.7,1.8,1.9,2.0,2.1, 3.49],我得到的答案[(0.4900000000000002, 1.4)]不正确。
  • 所以任何在01.9 之间开始的窗口在这个例子中都是有效的。即正确答案是[(0,1.9)]
  • 从 0.0 开始的大小为 3 的窗口将包含超过 4 个点的1.4, 1.5,1.6,1.7,1.8,1.9,2.0,2.1,因此是有效的。
  • 类似地,从1.9 开始的窗口包括至少满足4 个点的1.9,2.0,2.1, 3.49 点。
  • 我明白你的意思。我太专注于你的四点间隔。我有一个修复的想法,但现在没有时间来实现它。稍后再交。
猜你喜欢
  • 2021-12-27
  • 2016-01-10
  • 1970-01-01
  • 1970-01-01
  • 2017-01-24
  • 2021-07-22
  • 2011-11-23
  • 1970-01-01
  • 2011-08-26
相关资源
最近更新 更多