是否有像numpy.argmin(x)
这样的东西,但是对于中位数?
答案 0 :(得分:7)
快速近似:
json
答案 1 :(得分:6)
这似乎是一个老问题,但我找到了一个很好的方法来实现它:
import random
import numpy as np
#some random list with 20 elements
a = [random.random() for i in range(20)]
#find the median index of a
medIdx = a.index(np.percentile(a,50,interpolation='nearest'))
这里的巧妙技巧是最近插值的百分位内置选项,它从列表中返回“实际”中值,因此之后搜索它是安全的。
答案 2 :(得分:1)
您可以使用元素(zip
)保留索引,并对中间的中间或两个元素进行排序和返回,但排序将为O(n.logn)
。就时间复杂度而言,以下方法为O(n)
。
import numpy as np
def arg_median(a):
if len(a) % 2 == 1:
return np.where( a == np.median(a) )[0][0]
else:
l,r = len(a)/2 -1, len(a)/2
left = np.partition(a, l)[l]
right = np.partition(a, r)[r]
return [np.where(a == left)[0][0], np.where(a==right)[0][0]]
print(arg_median(np.array([ 3, 9, 5, 1, 15])))
# 1 3 5 9 15, median=5, index=2
print(arg_median(np.array([ 3, 9, 5, 1, 15, 12])))
# 1 3 5 9 12 15, median=5,9, index=2,1
输出:
2
[2, 1]
这个想法是,如果只有一个中位数(数组有一个奇数长度),那么它返回中位数的索引。如果我们需要对元素求平均值(数组具有偶数长度),那么它将返回列表中这两个元素的索引。
答案 3 :(得分:1)
通常,这是一个不适的问题,因为对于numpy定义的中值,数组不一定包含其自己的中值。例如:
>>> np.median([1, 2])
1.5
但是,当数组的长度为奇数时,中位数通常会在数组中,因此询问其索引确实有意义:
>>> np.median([1, 2, 3])
2
对于奇长数组,确定中值索引的有效方法是使用np.argpartition
函数。例如:
import numpy as np
def argmedian(x):
return np.argpartition(x, len(x) // 2)[len(x) // 2]
# Works for odd-length arrays, where the median is in the array:
x = np.random.rand(101)
print("median in array:", np.median(x) in x)
# median in array: True
print(x[argmedian(x)], np.median(x))
# 0.5819150016674371 0.5819150016674371
# Doesn't work for even-length arrays, where the median is not in the array:
x = np.random.rand(100)
print("median in array:", np.median(x) in x)
# median in array: False
print(x[argmedian(x)], np.median(x))
# 0.6116799104572843 0.6047559243909065
随着数组大小的增长,这比公认的基于排序的解决方案要快得多:
x = np.random.rand(1000)
%timeit np.argsort(x)[len(x)//2]
# 10000 loops, best of 3: 25.4 µs per loop
%timeit np.argpartition(x, len(x) // 2)[len(x) // 2]
# 100000 loops, best of 3: 6.03 µs per loop
答案 4 :(得分:1)
接受的答案 numpy.argsort(data)[len(data)//2]
无法处理包含 NaN 的数组。
对于二维数组,获取轴=1(沿行)中列索引的中位数:
df = pd.DataFrame({'a': [1, 2, 3.3, 4],
'b': [80, 23, np.nan, 88],
'c': [75, 45, 76, 67],
'd': [5, 4, 6, 7]})
data = df.to_numpy()
# data
array([[ 1. , 80. , 75. , 5. ],
[ 2. , 23. , 45. , 4. ],
[ 3.3, nan, 76. , 6. ],
[ 4. , 88. , 67. , 7. ]])
# median, ignoring NaNs
amedian = np.nanmedian(data, axis=1)
aabs = np.abs(data.T-amedian).T
idx = np.nanargmin(aabs, axis=1)
idx
array([2, 1, 3, 2])
# the accepted answer, please note the third index is 2, the correspnoding cell value is 76, which should not be the median value in row [ 3.3, nan, 76. , 6. ]
idx = np.argsort(data)[:, len(data[0])//2]
idx
array([2, 1, 2, 2])
由于这是一个偶数列的 4*4 数组,因此第 3 行的中值列索引应为 6 而不是 76。
答案 5 :(得分:0)
接受的答案numpy.argsort(data)[len(data)//2]
的问题在于它仅适用于一维数组。对于n维数组,我们需要使用基于@Hagay提出的答案的不同解决方案。
import numpy as np
# Initialize random 2d array, a
a = np.random.randint(0, 7, size=16).reshape(4,4)
array([[3, 1, 3, 4],
[5, 2, 1, 4],
[4, 2, 4, 2],
[6, 1, 0, 6]])
# Get the argmedians
np.stack(np.nonzero(a == np.percentile(a,50,interpolation='nearest')), axis=1)
array([[0, 0],
[0, 2]])
# Initialize random 3d array, a
a = np.random.randint(0, 10, size=27).reshape(3,3,3)
array([[[3, 5, 3],
[7, 4, 3],
[8, 3, 0]],
[[2, 6, 1],
[7, 8, 8],
[0, 6, 5]],
[[0, 7, 8],
[3, 1, 0],
[9, 6, 7]]])
# Get the argmedians
np.stack(np.nonzero(a == np.percentile(a,50,interpolation='nearest')), axis=1)
array([[0, 0, 1],
[1, 2, 2]])