有没有办法在一个命令中获取python中值的索引?

时间:2015-10-03 14:21:59

标签: python math numpy

是否有像numpy.argmin(x)这样的东西,但是对于中位数?

6 个答案:

答案 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]])