在Python中查找列表的中位数

280

如何在Python中找到列表的中位数?该列表可以是任意大小,并且数字不保证按任何特定顺序排列。

如果列表包含偶数个元素,则函数应返回中间两个元素的平均值。

以下是一些示例(为了显示目的而排序):

median([1]) == 1
median([1, 1]) == 1
median([1, 1, 2, 4]) == 1.5
median([0, 2, 5, 6, 8, 9, 9]) == 6
median([0, 0, 0, 0, 4, 4, 6, 8]) == 2

2
选择算法 - amit
13
这里的答案很好,所以我认为我想让这个问题大致成为寻找中位数的规范答案,(主要是为了能够关闭这个问题)。请注意,该问题已经有了30,000个浏览量。如果这个问题没有被关闭或遗忘,我将不胜感激,因为它可以继续出现在搜索结果中并吸引那些浏览量。 - Veedrac
28个回答

5
我在Python实现的“中位数中位数”算法发布了我的解决方案,它比使用sort()函数稍微快一些。我的解决方案每列使用15个数字,速度为~5N,比每列使用5个数字的速度~10N更快。最优速度为~4N,但我可能有所错误。
根据Tom的评论请求,我在此处添加了我的代码以供参考。我认为速度的关键部分是每列使用15个数字,而不是5个。
#!/bin/pypy
#
# TH @stackoverflow, 2016-01-20, linear time "median of medians" algorithm
#
import sys, random


items_per_column = 15


def find_i_th_smallest( A, i ):
    t = len(A)
    if(t <= items_per_column):
        # if A is a small list with less than items_per_column items, then:
        #
        # 1. do sort on A
        # 2. find i-th smallest item of A
        #
        return sorted(A)[i]
    else:
        # 1. partition A into columns of k items each. k is odd, say 5.
        # 2. find the median of every column
        # 3. put all medians in a new list, say, B
        #
        B = [ find_i_th_smallest(k, (len(k) - 1)/2) for k in [A[j:(j + items_per_column)] for j in range(0,len(A),items_per_column)]]

        # 4. find M, the median of B
        #
        M = find_i_th_smallest(B, (len(B) - 1)/2)


        # 5. split A into 3 parts by M, { < M }, { == M }, and { > M }
        # 6. find which above set has A's i-th smallest, recursively.
        #
        P1 = [ j for j in A if j < M ]
        if(i < len(P1)):
            return find_i_th_smallest( P1, i)
        P3 = [ j for j in A if j > M ]
        L3 = len(P3)
        if(i < (t - L3)):
            return M
        return find_i_th_smallest( P3, i - (t - L3))


# How many numbers should be randomly generated for testing?
#
number_of_numbers = int(sys.argv[1])


# create a list of random positive integers
#
L = [ random.randint(0, number_of_numbers) for i in range(0, number_of_numbers) ]


# Show the original list
#
# print L


# This is for validation
#
# print sorted(L)[int((len(L) - 1)/2)]


# This is the result of the "median of medians" function.
# Its result should be the same as the above.
#
print find_i_th_smallest( L, (len(L) - 1) / 2)

4

如果您需要有关列表分布的其他信息,百分位数方法可能会有用。中位数对应于列表的第50个百分位数:

import numpy as np
a = np.array([1,2,3,4,5,6,7,8,9])
median_value = np.percentile(a, 50) # return 50th percentile
print median_value 

3

我在Codecademy的练习中得出了以下内容:

def median(data):
    new_list = sorted(data)
    if len(new_list)%2 > 0:
        return new_list[len(new_list)/2]
    elif len(new_list)%2 == 0:
        return (new_list[(len(new_list)/2)] + new_list[(len(new_list)/2)-1]) /2.0

print median([1,2,3,4,5,9])

3

只需要两行就足够了。

def get_median(arr):
    '''
    Calculate the median of a sequence.
    :param arr: list
    :return: int or float
    '''
    arr = sorted(arr)
    return arr[len(arr)//2] if len(arr) % 2 else (arr[len(arr)//2] + arr[len(arr)//2-1])/2

2

中位数函数

def median(midlist):
    midlist.sort()
    lens = len(midlist)
    if lens % 2 != 0: 
        midl = (lens / 2)
        res = midlist[midl]
    else:
        odd = (lens / 2) -1
        ev = (lens / 2) 
        res = float(midlist[odd] + midlist[ev]) / float(2)
    return res

2
def midme(list1):

    list1.sort()
    if len(list1)%2>0:
            x = list1[int((len(list1)/2))]
    else:
            x = ((list1[int((len(list1)/2))-1])+(list1[int(((len(list1)/2)))]))/2
    return x


midme([4,5,1,7,2])

2

我在处理浮点数列表时遇到了一些问题。最终,我使用了python3的statistics.median中的代码片段,它对于没有导入的浮点值完美地运行。 源码

def calculateMedian(list):
    data = sorted(list)
    n = len(data)
    if n == 0:
        return None
    if n % 2 == 1:
        return data[n // 2]
    else:
        i = n // 2
        return (data[i - 1] + data[i]) / 2

1
def median(array):
    if len(array) < 1:
        return(None)
    if len(array) % 2 == 0:
        median = (array[len(array)//2-1: len(array)//2+1])
        return sum(median) / len(median)
    else:
        return(array[len(array)//2])

3
虽然这段代码可能回答了问题,但如果提供有关为什么和/或如何回答问题的其他上下文信息,可以提高其长期价值。 - rollstuhlfahrer
1
非常抱歉!我刚刚开始使用 Stack Overflow,不知道如何添加摘要... - Luke Willey
点击您的帖子下方的“编辑”链接,添加摘要,然后保存。 - Robert Columbia

0
我为一组数字定义了一个中位数函数,代码如下:
def median(numbers):
    return (sorted(numbers)[int(round((len(numbers) - 1) / 2.0))] + sorted(numbers)[int(round((len(numbers) - 1) // 2.0))]) / 2.0

这里存在可避免的函数调用重复,这可能会非常耗费时间。 - Asclepius

0

试一下

import math
def find_median(arr):
    if len(arr)%2==1:
        med=math.ceil(len(arr)/2)-1
        return arr[med]
    else:
        return -1
print(find_median([1,2,3,4,5,6,7,8]))

1
这需要一个已排序的数组吗? - Asclepius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接