【问题标题】:Finding the position of the median of an array containing mostly zeros查找包含大部分零的数组的中位数的位置
【发布时间】:2018-09-19 06:49:55
【问题描述】:

我有一个非常大的一维数组,其中大多数元素为零,而非零元素都聚集在由许多零分隔的几个岛周围:(这里是一个较小的版本,用于 MWE)

In [1]: import numpy as np

In [2]: A=np.array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,20,14,10,5,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,5,5,18,18,16,14,10,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,3,6,16,4,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])

我想根据每个岛的中值对应的索引找到中值及其位置(甚至是近似值)。毫不奇怪,我得到了零,这不是我想要的:

In [3]: np.median(A)
Out[3]: 0.0

In [4]: np.argsort(A)[len(A)//2]
Out[4]: 12

在单个非零元素岛的情况下,为了解决这个警告并满足我的要求,即只有非零元素在物理上有意义,我首先删除所有零,然后取剩余元素的中位数:

In [5]: masks = np.where(A>0)
In [6]: A[masks]
Out[6]: array([ 1,  3,  6, 20, 14, 10,  5,  1])

这一次,我正确地得到了新数组的中位数,但是位置(索引)将不正确,因为它很明显,并且在 cmets 中也指出在数学上定义不明确。

In [7]: np.median(A[masks])
Out[7]: 5.5

In [8]: np.argsort(A[masks])[len(A[masks])//2]
Out[8]: 2

根据这个近似值,我知道实际中位数位于修改后数组的第三个索引中,但我想将其转换回原始数组的格式,其中中位数的位置(索引)应该在某处在对应于较大索引的非零元素的第一个岛的中间(其中零索引都被正确计算)。在 cmets 中还回答了两个建议,以在零海中间给定一个非零元素岛的情况下提出中位数的位置。但是,如果有不止一个这样的岛屿呢?怎么可能在原始的直方图数组的上下文中计算每个岛的中位数对应的索引,其中所有的零都被计算在内?

我想知道是否有任何简单的方法来计算这些许多零的数组中的中位数的位置。如果没有,在知道修改后的数组中的位置后,我还应该在我的代码行中添加什么以使其成为可能?非常感谢您的帮助。

【问题讨论】:

  • np.median(masks) 怎么样?预期的 o/p 是多少?如果有多个非零的情况如何?
  • 亲爱的沃伦,你是对的。但我只对非零元素感兴趣。但我碰巧需要的唯一一条信息是在原始数组中用零定位这个中值。我猜 Divakar 的评论将被视为一个答案。
  • 亲爱的 Miradulo,这将给我提供两倍大的东西。
  • 中位数的“位置”不是一个明确定义的量。 [3, 8, 9, 7, 2, 1, 9, 7] 的中位数是 7,但是如何定义它的位置呢?
  • A 实际上是一个直方图(即一个计数数组),你想要计算值的中位数吗?那么也许像np.searchsorted(A.cumsum(), A.sum()/2) 这样的东西会起作用。

标签: python-3.x sorting numpy indexing median


【解决方案1】:

基于评论“A 实际上是一个带有许多 bin 的离散直方图”,我认为您想要的是正在计算的值的中位数。如果A 是一个整数数组,那么中位数的精确(但可能非常低效,如果您的值高达 1e7)公式是

np.median(np.repeat(np.arange(len(A)), A))  # Do not use if A contains very large values!

或者,您可以使用

np.searchsorted(A.cumsum(), 0.5*A.sum())

这将是中位数的整数部分。

例如:

In [157]: A
Out[157]: 
array([ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  3,
        6, 20, 14, 10,  5,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0])

In [158]: np.median(np.repeat(np.arange(len(A)), A))
Out[158]: 35.5

In [159]: np.searchsorted(A.cumsum(), 0.5*A.sum())
Out[159]: 35

另一个例子:

In [167]: B
Out[167]: 
array([  0,   0,   0,   1, 100,  21,   8,   3,   2,   1,   0,   0,   0,
         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
         0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0])

In [168]: np.median(np.repeat(np.arange(len(B)), B))
Out[168]: 4.0

In [169]: np.searchsorted(B.cumsum(), 0.5*B.sum())
Out[169]: 4

【讨论】:

  • 感谢亲爱的沃伦您的全面回答。我刚刚编辑了这个问题,因此它包含多个非零元素岛。您能否修改您的答案以反映这一点?
  • 这一变化使问题更加复杂。现在您要识别“集群”,并计算每个集群的中值。我的答案没有简单的修改可以做到这一点。在您识别出每个集群后,此答案可以应用于每个集群。但是识别集群应该是一个新的 SO 问题(当然,在你尝试让它自己工作之后)。
猜你喜欢
  • 2012-11-20
  • 1970-01-01
  • 2017-12-16
  • 2013-01-29
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多