【问题标题】:Getting rid of redundant 2D points without losing order在不丢失顺序的情况下摆脱多余的 2D 点
【发布时间】:2020-06-02 22:57:14
【问题描述】:

我有以下几点:

import numpy as np
points = np.array([[49.8, 66.35],
 [49.79, 66.35],
 [49.79, 66.35],
 [44.65, 67.25],
 [44.65, 67.25],
 [44.65, 67.25],
 [44.48, 67.24],
 [44.63, 67.21],
 [44.68, 67.2],
 [49.69, 66.21],
 [49.85, 66.17],
 [50.51, 66.04],
 [49.8, 66.35]])

当我绘制它们时,我得到了这个形状:

import matplotlib.pyplot as plt
x = [a[0] for a in points ]
y = [a[1] for a in points ]
plt.plot(x,y)

从点列表中可以看出,其中一些是多余的(即查看点 1 和 2(从 0 开始))。

为了只保留非冗余点,我回复了这个问题的答案: Removing duplicate columns and rows from a NumPy 2D array

def unique_2D(a):
    order = np.lexsort(a.T)
    a = a[order]
    diff = np.diff(a, axis=0)
    ui = np.ones(len(a), 'bool')
    ui[1:] = (diff != 0).any(axis=1) 
    return a[ui]

我将这个函数应用到我的积分上,我得到:

non_redundant_points = unique_2D(points)

这是打印的保留点列表:

[[ 50.51  66.04]
 [ 49.85  66.17]
 [ 49.69  66.21]
 [ 49.79  66.35]
 [ 49.8   66.35]
 [ 44.68  67.2 ]
 [ 44.63  67.21]
 [ 44.48  67.24]
 [ 44.65  67.25]]

但是,现在我面临以下问题:当我绘制它们时,订单不知何故没有保留......

x_nr = [a[0] for a in non_redundant_points ]
y_nr = [a[1] for a in non_redundant_points ]
plt.plot(x_nr,y_nr)

你知道我该如何解决这个问题吗?

为了方便复制和粘贴,这里是完整的代码:

import numpy as np    
import matplotlib.pyplot as plt

points = np.array([[49.8, 66.35],
 [49.79, 66.35],
 [49.79, 66.35],
 [44.65, 67.25],
 [44.65, 67.25],
 [44.65, 67.25],
 [44.48, 67.24],
 [44.63, 67.21],
 [44.68, 67.2],
 [49.69, 66.21],
 [49.85, 66.17],
 [50.51, 66.04],
 [49.8, 66.35]])

x = [a[0] for a in points ]
y = [a[1] for a in points ]
plt.plot(x,y)

def unique_2D(a):
        order = np.lexsort(a.T)
        a = a[order]
        diff = np.diff(a, axis=0)
        ui = np.ones(len(a), 'bool')
        ui[1:] = (diff != 0).any(axis=1) 
        return a[ui]

x_nr = [a[0] for a in non_redundant_points ]
y_nr = [a[1] for a in non_redundant_points ]
plt.plot(x_nr,y_nr)

【问题讨论】:

  • 为什么不简单地遍历点,如果一个点与前一个相同,跳过它?
  • 假设最后一个坐标是 [49.79, 66.35] 而不是 [49.80, 66.35];你想摆脱它,因为它以前出现过吗?还是您只想保留相邻的相同值?我们需要担心浮点精度吗?如果其中一个数字是 [49.79000001, 66.34999998],是否算作 [49.79, 66.35] 的重复?

标签: python list numpy matplotlib


【解决方案1】:

您可以使用np.unique 获取唯一元素,使用return_index=True 获取原始数组的索引。然后您可以使用它们对返回的唯一数组进行排序以获得原始索引顺序

points = np.array([[49.8, 66.35],
                   [49.79, 66.35],
                   [49.79, 66.35], ... ] # Your original input array

points, idx = np.unique(points, axis=0, return_index=True)
print (idx)
# [ 6  7  3  8  9  1  0 10 11]


arr = points[np.argsort(idx), :]

print (arr)

# [[49.8  66.35]
#  [49.79 66.35]
#  [44.65 67.25]
#  [44.48 67.24]
#  [44.63 67.21]
#  [44.68 67.2 ]
#  [49.69 66.21]
#  [49.85 66.17]
#  [50.51 66.04]]

绘制它们

plt.plot(arr[:, 0], arr[:, 1])

【讨论】:

    【解决方案2】:

    您可以跟踪您看到的set 中已经存在的点。为此,您可以创建一个允许散列和比较点的类:

    In [93]: class Point:
    ...:     def __init__(self, x, y):
    ...:         self.x=x
    ...:         self.y=y
    ...:     def __hash__(self):
    ...:         return hash((self.x, self.y))
    ...:     def __eq__(self, other):
    ...:         return self.x == other.x and self.y == other.y
    ...:     def __str__(self):
    ...:         return f'({self.x}, {self.y})'
    ...:     def __repr__(self):
    ...:         return str(self)
    ...:
    
    In [94]: points = [[49.8, 66.35],
    ...:  [49.79, 66.35],
    ...:  [49.79, 66.35],
    ...:  [44.65, 67.25],
    ...:  [44.65, 67.25],
    ...:  [44.65, 67.25],
    ...:  [44.48, 67.24],
    ...:  [44.63, 67.21],
    ...:  [44.68, 67.2],
    ...:  [49.69, 66.21],
    ...:  [49.85, 66.17],
    ...:  [50.51, 66.04],
    ...:  [49.8, 66.35]]
    

    现在我们可以将点转换为Point's的数组

    In [95]: points = [Point(*p) for p in points]
    In [96]: points
    Out[96]:
    [(49.8, 66.35),
     (49.79, 66.35),
     (49.79, 66.35),
     (44.65, 67.25),
     (44.65, 67.25),
     (44.65, 67.25),
     (44.48, 67.24),
     (44.63, 67.21),
     (44.68, 67.2),
     (49.69, 66.21),
     (49.85, 66.17),
     (50.51, 66.04),
     (49.8, 66.35)]
    

    我们现在需要做的就是遍历这些点,如果我们还没有看到它,将其添加到 unique 列表中

    In [102]: seen = set()
    
    In [103]: new_points = []
    
    In [104]: for point in points:
         ...:     if point not in seen:
         ...:         new_points.append(point)
         ...:         seen.add(point)
         ...:
    
    In [105]: new_points
    Out[105]:
    [(49.8, 66.35),
     (49.79, 66.35),
     (44.65, 67.25),
     (44.48, 67.24),
     (44.63, 67.21),
     (44.68, 67.2),
     (49.69, 66.21),
     (49.85, 66.17),
     (50.51, 66.04)]
    

    现在你已经保持了秩序,没有重复点。

    编辑:我想我误读了部分问题。我想你只是想忽略顺序集?如,仅在另一个点之后立即重复点,但如果它在最后,那么你想保留它。如果是这种情况,您可以这样做:

    In [114]: new_points = [points[0]]
    
    In [115]: repeat = new_points[0]
    
    In [116]: for point in points[1:]:
         ...:     # New point found, i.e. not a repeat from previous sequential set
         ...:     if point != repeat:
         ...:         repeat = point
         ...:         new_points.append(point)
         ...:
    
    In [117]: new_points
    Out[117]:
    [(49.8, 66.35),
     (49.79, 66.35),
     (44.65, 67.25),
     (44.48, 67.24),
     (44.63, 67.21),
     (44.68, 67.2),
     (49.69, 66.21),
     (49.85, 66.17),
     (50.51, 66.04),
     (49.8, 66.35)]
    

    然后将其转换为绘图:

    points = np.array([[p.x, p.y] for p in new_points])
    plt.plot(points[:,0], points[:,1])
    

    【讨论】:

    • 你为什么需要一个类来做呢?为什么不直接使用points=map(tuple,points)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 2023-03-28
    • 1970-01-01
    • 2019-10-17
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    相关资源
    最近更新 更多