【问题标题】:Vectorized numpy 1-d reclassification向量化的 numpy 1-d 重新分类
【发布时间】:2017-03-30 11:34:19
【问题描述】:

我有一个包含大约 700,000 个类的大型 numpy 1-d。此外,我还有另一个类似大小的数组,其中包含类的新值。

示例数组

original_classes = np.array([0,1,2,3,4,5,6,7,8,9,10,10])
new_classes = np.array([1,0,1,2,2,10,1,6,6,9,5,12])

期望的输出

>>> reclassify_function(original_classes, new_classes)
array([ 1,  1,  1,  1,  1, 12,  1,  1,  9, 12, 12])

困难在于存在多个类关系。

原来的类 1 应该得到一个新的值 0,这意味着 0 和 1 是相等的类,并且这些值的所有出现都应该分配给同一个新的类号。原类 2 应归类为 1,这意味着类 2 等于类 0 和类 1。因此原类 0-2 应分配给相同的新类号等...

由于我正在处理大型数组,我希望重新分类函数被矢量化。

【问题讨论】:

  • 包含 70,000 个项目的数组?它一点也不大。尝试使用循环实现。如果你做对了,如果你对性能不满意,请在此处发布。
  • 对不起,应该是 700,000。已经在研究循环方法了!
  • 这将占用大约 2.7MB 的内存。还是没那么大。
  • 在您的示例中,1 变为 0,0 变为 1。这不是无限循环吗?
  • 我只是想指出 0 和 1(以及 2 和 6)是同一个类。他们被分配到哪个新班级编号并不重要。对于代码示例,您可以查看未矢量化方法。

标签: python arrays numpy classification vectorization


【解决方案1】:

您可以使用scipy.sparse.csgraph.connected_components 重新标记您的课程。对于您的示例数据:

from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import connected_components

A = np.array([0,1,2,3,4,5, 6,7,8,9,10,10])
B = np.array([1,0,1,2,2,10,1,6,6,9,5 ,12])

N = max(A.max(), B.max()) + 1
weights = np.ones(len(A), int)
graph = csr_matrix((weights, (A, B)), shape=(N, N))
n_remaining, mapping = connected_components(graph, directed=False)
print mapping[A]

给予:

[0 0 0 0 0 1 0 0 0 2 1 1]

这些是重新标记的类。我相信您可以弄清楚如何根据输入数据来表达这些。请注意,为了获得最佳性能,“原始”和“新”类应该是一个连续整数范围,没有间隙。

【讨论】:

  • 不错!即使使用非连续值,此方法也会正确地重新标记类。您确定它们需要连续吗?
  • @Wilmar - 这是为了获得最佳性能。在我的代码中,mapping 将是一个长度为 N 的数组,因此如果输入有数十亿个未使用的分类,它将是一个比必要的大得多的数组,因此效率低下。一些小的差距不会对性能产生太大影响。但是n_remaining 也包括未使用的类,mapping[A] 很可能也不连续。
【解决方案2】:

这不是矢量化解决方案,在我的笔记本电脑上花了大约一个小时。这将创建一个集合列表调用class_sets;每个集合都是等效类的集合。

original_classes = np.random.randint(0,20000,700000)
new_classes = np.random.randint(0,20000,700000)
pairs = zip(original_classes, new_classes)
class_sets = [set(next(pairs))]

for i,p in enumerate(pairs):
    ps = set(p)
    intsect = [ps.intersection(cs) for cs in class_sets]
    if any([ps.intersection(cs) for cs in class_sets]):
        index = np.argmax(intsect)
        class_sets[index] = class_sets[index].union(ps)
    else:
        class_sets.append(ps)

【讨论】:

  • 谢谢,明天我将测试我的方法并将其与您的结果进行比较!
  • 你的方法报错所以我没有测试出来
猜你喜欢
  • 1970-01-01
  • 2017-04-04
  • 2016-02-08
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
相关资源
最近更新 更多