파이썬에서리스트의 중간 값 찾기


181

파이썬에서 목록의 중앙값을 어떻게 찾습니까? 목록의 크기는 다양 할 수 있으며 숫자는 특정 순서로 보장되지 않습니다.

목록에 짝수 개의 요소가 포함 된 경우 함수는 중간 2의 평균을 반환해야합니다.

다음은 몇 가지 예입니다 (표시 목적으로 정렬).

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


9
나는이 대략 중간 값을 찾기위한 정규 해답이 될하려는 생각 때문에 여기에 대한 대답은, 좋은 주로 그래서이를 닫습니다 수 있습니다 . 이 질문에 대한 조회수 는 3 만회 입니다. 이 질문이 어떤 식 으로든 닫히거나 간과되지 않아서 검색 결과에 머무르고 대신 그 견해를 빨아 들일 수 있다면 감사하겠습니다.
Veedrac

답변:


214

파이썬 3.4있다 statistics.median:

숫자 데이터의 중앙값 (중간 값)을 반환합니다.

데이터 포인트 수가 홀수이면 중간 데이터 포인트를 반환합니다. 데이터 포인트 수가 짝수 인 경우 두 중간 값의 평균을 취하여 중앙값을 보간합니다.

>>> median([1, 3, 5])
3
>>> median([1, 3, 5, 7])
4.0

용법:

import statistics

items = [6, 1, 8, 2, 3]

statistics.median(items)
#>>> 3

유형에 대해서도 매우 신중합니다.

statistics.median(map(float, items))
#>>> 3.0

from decimal import Decimal
statistics.median(map(Decimal, items))
#>>> Decimal('3')

완벽 pip3 install itunizer합니다. 중간 데이터를 쿼리 결과 에 추가하기 위해 추가했습니다 . 건배
jamescampbell

정렬 된 배열의 중앙값을 찾으려면 어떻게해야합니까? 내장 함수 statistics.median은 다시 정렬하는 동안 속도가 느려지므로 사용할 수 없습니다.
GilbertS

2
@GilbertS 그런 다음 중간 요소를 보거나 중간 두 개를 평균하십시오.
Veedrac

163

(와 일하다 ) :

def median(lst):
    n = len(lst)
    s = sorted(lst)
    return (sum(s[n//2-1:n//2+1])/2.0, s[n//2])[n % 2] if n else None

>>> median([-5, -5, -3, -4, 0, -1])
-3.5

numpy.median():

>>> from numpy import median
>>> median([1, -4, -1, -1, 1, -3])
-1.0

에 대한 , 사용 statistics.median:

>>> from statistics import median
>>> median([5, 2, 3, 8, 9, -2])
4.0

9
함수를 작성하지는 않지만, 여전히 "
파이 토닉

6
@dartdog 실제로는 아닙니다. 정당한 이유없이 Numpy 배열로 강제 변환하는 것은 바람직하지 않습니다. 당신은 타입을 강요했고, 더 나쁜 것은, 임의의 타입에 대한 지원을 잃었습니다.
Veedrac

1
유용한 포인트.
다트 독

3
그러나이 기능은 필요한 것보다 훨씬 힘들다.
Martijn Pieters

3
PEP 450 은 라이브러리를 사용하지 않는 것에 대해 좋은 주장을합니다. 결국 실수 할 것입니다.
Alex Harvey

51

sorted () 함수는 매우 유용합니다. 정렬 된 함수를 사용하여 목록을 정렬 한 다음 중간 값을 반환하거나 목록에 짝수의 요소가 포함 된 경우 두 중간 값의 평균을 계산하면됩니다.

def median(lst):
    sortedLst = sorted(lst)
    lstLen = len(lst)
    index = (lstLen - 1) // 2

    if (lstLen % 2):
        return sortedLst[index]
    else:
        return (sortedLst[index] + sortedLst[index + 1])/2.0

비록 비효율적입니다 : 정렬은 중앙값 (Theta (n))을 선택하는 것보다 최악의 경우 (Theta (n lg n))에 훨씬 더 많은 작업입니다 ...
Jeremy

12

더 깨끗한 해결책은 다음과 같습니다.

def median(lst):
    quotient, remainder = divmod(len(lst), 2)
    if remainder:
        return sorted(lst)[quotient]
    return sum(sorted(lst)[quotient - 1:quotient + 1]) / 2.

참고 : 답변은 의견에 제안을 포함하도록 변경되었습니다.


7
float(sum(…) / 2)로 교체해야합니다 sum(…) / 2.0. 그렇지 않으면 sum(…)정수인 경우 정수 몫의 float 버전을 얻게됩니다. 예를 들면 다음과 같습니다 float(sum([3, 4]) / 2)이다 3.0, 그러나 sum([3, 4]) / 2.0입니다 3.5.
musiphil

완전성을 위해 @musiphil : 파이썬 2에서만, 그리고 당신이하지 않은 경우에만 from __future__ import division.
Chris L. Barnes

11

더 빠른 평균 사례 실행 시간이 필요한 경우 quickselect 알고리즘을 시도 할 수 있습니다 . Quickselect는 좋지 않은 날에 O(n)종료 될 수 있지만 평균 (및 최상의) 성능을 제공 O(n²)합니다.

다음은 임의로 선택된 피벗을 사용한 구현입니다.

import random

def select_nth(n, items):
    pivot = random.choice(items)

    lesser = [item for item in items if item < pivot]
    if len(lesser) > n:
        return select_nth(n, lesser)
    n -= len(lesser)

    numequal = items.count(pivot)
    if numequal > n:
        return pivot
    n -= numequal

    greater = [item for item in items if item > pivot]
    return select_nth(n, greater)

이것을 중간 값을 찾는 방법으로 간단하게 바꿀 수 있습니다.

def median(items):
    if len(items) % 2:
        return select_nth(len(items)//2, items)

    else:
        left  = select_nth((len(items)-1) // 2, items)
        right = select_nth((len(items)+1) // 2, items)

        return (left + right) / 2

이것은 매우 unoptimised이지만, 심지어 최적화 된 버전 정렬 팀을 능가 할 가능성이 아니에요 (CPython과의 내장에서 sort) 그 때문에 정말 빨리 . 나는 전에 시도했지만 잃었다.


sort ()가 더 빠르다면 왜 이것에 대해 생각해야합니까?
최대

@Max PyPy 또는 일부 유형을 사용하는 경우 sort쉽게 할 수 없거나 속도 등을 위해 C 확장을 작성하려고합니다.
Veedrac

10

물론 당신은 함수로 빌드를 사용할 수 있지만, 당신이 직접 만들고 싶다면 이런 식으로 할 수 있습니다. 여기서 트릭은 양수를 음수로 뒤집는 ~ 연산자를 사용하는 것입니다. 예를 들어 ~ 2-> -3이고 Python에서 list에 negative in을 사용하면 끝부터 항목을 계산합니다. 따라서 중간 == 2 인 경우 처음부터 세 번째 요소와 끝에서 세 번째 항목이 필요합니다.

def median(data):
    data.sort()
    mid = len(data) // 2
    return (data[mid] + data[~mid]) / 2

8

를 사용하여 list.sort새 목록을 작성하지 않고 목록을 sorted정렬 할 수 있습니다 .

또한 list파이썬 자체 목록을 가리기 때문에 변수 이름으로 사용해서는 안됩니다 .

def median(l):
    half = len(l) // 2
    l.sort()
    if not len(l) % 2:
        return (l[half - 1] + l[half]) / 2.0
    return l[half]

5
간단한 유틸리티 함수는 인수를 변경하지 않아야합니다 (특히 함수 이름이 명사 IMO 인 경우). sorted over .sort ()를 사용하면 인수가 목록 일 필요는 없습니다. 반복자가 될 수 있습니다.
Will S

1
내 요점은 목록을 변경하는 함수에 관한 것입니다. 나는 일종의 좋은 부작용으로 iterable을 지원한다고 언급했지만 주요 이점은 아닙니다. 나는 중간 (목록)이 거의 모든 다른 내장 또는 수학 함수처럼 작동 할 것으로 기대합니다. next ()는 변이되지만 다른 것은 생각할 수 없습니다. 놀람 돌연변이는 디버깅을 위해 엉덩이에 고통입니다.
Will S

@ WillS, 문서화 될 때 어떻게 놀랍습니까? 대용량 데이터를 처리하거나 메모리 용량이 제한되어 있고 목록의 사본을 만들 수 없으면 어떻게해야합니까?
Padraic Cunningham

2
함수가 정렬 된 목록을 기대하도록하고이를 문서화하십시오. mylist.sort(); middle(mylist)그러나 그것은 틀림없이 맛의 문제입니다. 나는 일반적으로 돌연변이가 가능한 한 방법을 위해 예약되어야한다고 생각합니다. list.sort ()가 목록 자체 대신 None을 반환하는 이유는 동작을 최대한 명확하고 명확하게하기위한 것입니다. 문서에서 모든 것을 숨기는 것은 작은 인쇄물에 물건을 숨기는 것과 같습니다.
Will S


7
def median(array):
    """Calculate median of the given list.
    """
    # TODO: use statistics.median in Python 3
    array = sorted(array)
    half, odd = divmod(len(array), 2)
    if odd:
        return array[half]
    return (array[half - 1] + array[half]) / 2.0

7
def median(x):
    x = sorted(x)
    listlength = len(x) 
    num = listlength//2
    if listlength%2==0:
        middlenum = (x[num]+x[num-1])/2
    else:
        middlenum = x[num]
    return middlenum

1
첫 번째 코드 줄이 누락 된 것처럼 보입니다. 게시물을 편집하고 4 개의 공백으로 함수 헤더를 들여 쓰기하면이 문제를 해결할 수 있습니다.
요한

4

"중간 값 중앙값"알고리즘의 Python 구현 에서 솔루션을 게시했습니다. 했는데 sort ()를 사용하는 것보다 약간 빠릅니다. 내 솔루션은 열 당 15 개의 숫자를 사용하며 ~ 5N의 속도는 열 당 5 개의 숫자를 사용하는 ~ 10N의 속도보다 빠릅니다. 최적의 속도는 ~ 4N이지만 틀릴 수 있습니다.

그의 의견에 Tom의 요청에 따라, 참조를 위해 여기에 내 코드를 추가했습니다. 속도의 중요한 부분은 열 대신 15 개 열을 사용한다고 생각합니다.

#!/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)

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

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

float 값 목록에 문제가있었습니다. python3 statistics.median 의 코드 스 니펫을 사용하여 가져 오기없이 float 값으로 완벽하게 작동합니다. 출처

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

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

1

숫자 목록의 중간 함수를 다음과 같이 정의했습니다.

def median(numbers):
    return (sorted(numbers)[int(round((len(numbers) - 1) / 2.0))] + sorted(numbers)[int(round((len(numbers) - 1) // 2.0))]) / 2.0

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
나는 매우 미안 해요! 방금 스택 오버플로를 시작했는데 요약을 추가하는 방법을 모르겠습니다 ....
Luke Willey

게시물 아래의 "수정"링크를 클릭하고 요약을 추가 한 다음 저장하십시오.
Robert Columbia

1

기능 중앙값 :

def median(d):
    d=np.sort(d)
    n2=int(len(d)/2)
    r=n2%2
    if (r==0):
        med=d[n2] 
    else:
        med=(d[n2] + data[m+1]) / 2
    return med

1

목록 배포에 대한 추가 정보가 필요한 경우 백분위 수 방법이 유용 할 것입니다. 그리고 중앙값은리스트의 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 

1

주어진 목록의 중앙값을 반환하는 간단한 함수 :

def median(lsts):
        if len(lsts)%2 == 0:  #Checking if the length is even
            return (lsts[len(lsts)//2] + lsts[(len(lsts) - 1) //2]) //2 # Applying formula which is sum of middle two divided by 2
            
        else:
            return lsts[len(lsts)//2] # If length is odd then get middle value
            
        
median([2,3,5,6,10]) #Calling function

라이브러리를 사용하려면 간단히 할 수 있습니다.

import statistics

statistics.median([9, 12, 20, 21, 34, 80])

0
import numpy as np
def get_median(xs):
        mid = len(xs) // 2  # Take the mid of the list
        if len(xs) % 2 == 1: # check if the len of list is odd
            return sorted(xs)[mid] #if true then mid will be median after sorting
        else:
            #return 0.5 * sum(sorted(xs)[mid - 1:mid + 1])
            return 0.5 * np.sum(sorted(xs)[mid - 1:mid + 1]) #if false take the avg of mid
print(get_median([7, 7, 3, 1, 4, 5]))
print(get_median([1,2,3, 4,5]))

0

중앙값 (및 백분위 수)에 대한보다 일반적인 접근 방식은 다음과 같습니다.

def get_percentile(data, percentile):
    # Get the number of observations
    cnt=len(data)
    # Sort the list
    data=sorted(data)
    # Determine the split point
    i=(cnt-1)*percentile
    # Find the `floor` of the split point
    diff=i-int(i)
    # Return the weighted average of the value above and below the split point
    return data[int(i)]*(1-diff)+data[int(i)+1]*(diff)

# Data
data=[1,2,3,4,5]
# For the median
print(get_percentile(data=data, percentile=.50))
# > 3
print(get_percentile(data=data, percentile=.75))
# > 4

# Note the weighted average difference when an int is not returned by the percentile
print(get_percentile(data=data, percentile=.51))
# > 3.04

-2

median함수 를 사용하지 않고 중간 값을 찾는 지루한 방법은 다음과 같습니다 .

def median(*arg):
    order(arg)
    numArg = len(arg)
    half = int(numArg/2)
    if numArg/2 ==half:
        print((arg[half-1]+arg[half])/2)
    else:
        print(int(arg[half]))

def order(tup):
    ordered = [tup[i] for i in range(len(tup))]
    test(ordered)
    while(test(ordered)):
        test(ordered)
    print(ordered)


def test(ordered):
    whileloop = 0 
    for i in range(len(ordered)-1):
        print(i)
        if (ordered[i]>ordered[i+1]):
            print(str(ordered[i]) + ' is greater than ' + str(ordered[i+1]))
            original = ordered[i+1]
            ordered[i+1]=ordered[i]
            ordered[i]=original
            whileloop = 1 #run the loop again if you had to switch values
    return whileloop

이 버블 정렬입니까? 왜?
Ry-

왜 값을 바꾸고 있습니까?
ravi tanwar 5

-3

매우 간단합니다.

def median(alist):
    #to find median you will have to sort the list first
    sList = sorted(alist)
    first = 0
    last = len(sList)-1
    midpoint = (first + last)//2
    return midpoint

그리고 당신은 이런 식으로 반환 값을 사용할 수 있습니다 median = median(anyList)


1
중간 값은 중간 점을 찾기 전에 배열을 정렬해야합니다.
Saurabh Jain

sList정렬 된 배열을 반환합니다. 중앙값을 반환하지 않습니다
Farhan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.