Python'da listenin medyanını bulma


181

Python'da bir listenin medyanını nasıl buldunuz? Liste herhangi bir boyutta olabilir ve sayıların belirli bir sırada olması garanti edilmez.

Liste çift sayıda öğe içeriyorsa, işlev orta ikisinin ortalamasını döndürmelidir.

İşte bazı örnekler (görüntüleme amaçlı olarak sıralanmıştır):

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
Buradaki cevaplar iyi, bu yüzden bunun medyanları bulmak için kabaca kanonik bir cevap olmasını istiyorum, büyük ölçüde bunu kapatabilirim . Bu sorunun 30 bin görüşe sahip olduğunu unutmayın . Bu sorunun, arama sonuçlarında kalması ve bunun yerine bu görünümleri emebilmesi için herhangi bir şekilde kapatılmamış veya dağıtılmamış olup olmadığını takdir ediyorum.
Veedrac

Yanıtlar:


214

Python 3.4 şunları içerir statistics.median:

Sayısal verilerin medyanını (orta değer) döndür.

Veri noktalarının sayısı tek olduğunda, orta veri noktasını döndürün. Veri noktalarının sayısı eşit olduğunda, medyan iki orta değerin ortalaması alınarak enterpolasyon yapılır:

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

Kullanımı:

import statistics

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

statistics.median(items)
#>>> 3

Türler için de oldukça dikkatli:

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

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

Mükemmel, pip3 install itunizersorgu sonuçlarına medyan veri eklemek için eklemek için çalıştı . Şerefe
jamescampbell

Sıralanmış bir dizinin medyanını bulmak isterseniz ne olur? Bu yüzden yerleşik fonksiyon istatistiklerini kullanamazsınız. Çünkü tekrar sıralama yaparken yavaşlar
GilbertS

2
@GilbertS Sonra orta elemana bakın ya da orta ikisini ortalayın.
Veedrac

163

(İle çalışır ):

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

İçin , kullanın statistics.median:

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

9
Bir işlev yazmıyorken, hala daha "pythonic" bir çözüm
imho

6
@dartdog Pek değil; iyi bir neden olmadan bir Numpy dizisine zorlamak tavsiye edilmez. Tipleri zorladınız ve daha da kötüsü, keyfi tipler için desteği kaybettiniz.
Veedrac

1
Alınan puanlar, faydalı.
dartdog

3
Bununla birlikte, işlev olması gerekenden çok daha zahmetlidir.
Martijn Pieters

3
PEP 450 kütüphane kullanılmamasına karşı iyi bir argüman yapar. Sonunda bir hata yapacaksın.
Alex Harvey

51

Sort () işlevi bunun için çok yararlıdır. Listeyi sipariş etmek için sıralanmış işlevi kullanın, ardından yalnızca orta değeri döndürün (veya liste eşit miktarda öğe içeriyorsa iki orta değerin ortalamasını alın).

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

Yine de son derece verimsiz: sıralama en kötü durumda (Theta (n lg n)) medyanı (Theta (n)) seçmekten çok daha fazla iştir ...
Jeremy

12

İşte daha temiz bir çözüm:

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

Not: Yanıt, önerilere yorum eklemek için değiştirildi.


7
float(sum(…) / 2)ile değiştirilmelidir sum(…) / 2.0; aksi takdirde sum(…), bir tamsayı ise, tamsayı bölümünün kayan bir sürümünü alırsınız. Örneğin: float(sum([3, 4]) / 2)öyle 3.0, ama sum([3, 4]) / 2.0öyle 3.5.
musiphil

Tamlık için, @musiphil: sadece python 2'de ve sadece yapmadıysanız from __future__ import division.
Chris L. Barnes

11

Daha hızlı ortalama vaka çalışma süreleri gerekiyorsa hızlı seçim algoritmasını deneyebilirsiniz . Quickselect, kötü bir günde O(n)sonuçlanabilmesine rağmen ortalama (ve en iyi) vaka performansına sahiptir O(n²).

Rastgele seçilen bir pivot içeren bir uygulama:

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)

Bunu önemsiz bir şekilde medyan bulmak için bir yönteme dönüştürebilirsiniz:

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

Bu çok optimize edilmemiştir, ancak optimize edilmiş bir versiyonun bile Tim Sort'tan (CPython'un yerleşik sort) daha iyi performans göstermesi olası değildir, çünkü bu gerçekten hızlıdır . Daha önce denedim ve kaybettim.


Öyleyse, sort () daha hızlıysa neden bunu düşünelim?
Maksimum

@Max PyPy ya da bir çeşit kullanıyorsanız, sortkolayca, ya da hız, vb. İçin bir C uzantısı yazmaya istekli
değilseniz

10

Tabii ki yapı işlevlerini kullanabilirsiniz, ancak kendinizinkini oluşturmak istiyorsanız, böyle bir şey yapabilirsiniz. Buradaki hile, pozitif sayıyı negatife çeviren ~ operatörünü kullanmaktır. Örneğin ~ 2 -> -3 ve Python'daki listenin negatif girişini kullanmak, öğeleri sondan sayar. Eğer orta == 2 varsa, o zaman başından üçüncü eleman ve sondan üçüncü öğe alacaktır.

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

8

Sen kullanabilirsiniz list.sortyeni listeleri oluşturarak önlemek için sortedyerinde listeleri ve sıralama.

Ayrıca, listpython'un kendi listesini gölgelediği için değişken adı olarak kullanmamalısınız .

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
Basit yardımcı işlevler büyük olasılıkla herhangi bir argümanı değiştirmemelidir (Özellikle işlev adı bir isim IMO'su ise). Ayrıca sort .sort () yönteminin kullanılması, bağımsız değişkenin bir liste olması gerekmediği anlamına gelir. Herhangi bir yineleyici olabilir.
Will S

1
Demek istediğim, listeyi değiştiren fonksiyonla ilgiliydi. Sıralanabilir herhangi bir yan etkisi olarak herhangi bir yinelenebilir destek bahsetti, ama bu ana yararı değil. Biri için medyan (liste) 'nin neredeyse tüm diğer yerleşikler veya matematiksel fonksiyonlar gibi çalışmasını beklerim. next () değişiyor, ama başkalarını düşünemiyorum. Sürpriz mutasyon, hata ayıklama için kıçta bir ağrıdır.
Will S

@WillS, belgelenmesi nasıl bir sürpriz? Büyük verilerle uğraşıyorsanız veya sınırlı miktarda belleğiniz varsa ve listenin bir kopyasını yapamıyorsanız ne olacak?
Padraic Cunningham

2
İşlevin sıralı bir liste beklemesini sağlayın ve bunu belgeleyin. mylist.sort(); middle(mylist), ama inkar edilemez bir tat meselesi. Sadece mutasyonun mümkün olduğunca yöntemler için ayrılması gerektiğini düşünüyorum. List.sort () öğesinin, listenin kendisi yerine None döndürmesinin nedeni, davranışı olabildiğince açık ve net yapmaktır. Belgelerdeki her şeyi gizlemek, küçük boyutlu baskılardaki şeyleri gizlemek gibidir.
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
Görünüşe göre ilk kod satırınız dışarıda bırakılmış, yazınızı düzenleyerek çözebilir ve işlev başlığını 4 boşlukla girintileyebilirsiniz.
Johan

4

Çözümü Python'un "medyan medyan" algoritmasının uygulanmasında yayınladım. Bu, sort () kullanmaktan biraz daha hızlı. Çözümüm, sütun başına 5 sayı kullanmanın ~ 10N hızından daha hızlı olan ~ 5N hızı için sütun başına 15 sayı kullanır. Optimal hız ~ 4N, ancak bu konuda yanlış olabilirim.

Tom'un yorumundaki talebi üzerine, referans için kodumu buraya ekledim. Hızın kritik kısmının 5 yerine sütun başına 15 sayı kullandığını düşünüyorum.

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

İşte Codecademy'deki bu alıştırma sırasında neler buldum:

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

medyan İşlevi

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

Kayan nokta değerleri listelerinde bazı sorunlar yaşadım. Ben python3 statistics.median bir kod snippet kullanarak sona erdi ve ithalatı olmadan float değerleri ile mükemmel çalışıyor. kaynak

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

Sayı listesi için medyan fonksiyon olarak tanımladım

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
Bu kod soruyu cevaplayabilirken, bu kodun soruyu neden ve / veya nasıl cevapladığı konusunda ek bağlam sağlamak uzun vadeli değerini artırır.
rollstuhlfahrer

1
Çok üzgünüm! Az önce başladım, Stack Overflow ve nasıl özet ekleyeceğimi bilmiyorum ....
Luke Willey

Yayınınızın altındaki "Düzenle" bağlantısını tıklayın ve bir özet ekleyin, ardından kaydedin.
Robert Columbia

1

fuction medyan:

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

Listenizin dağıtımı hakkında daha fazla bilgiye ihtiyaç duymanız durumunda, yüzdelik yöntemi muhtemelen yararlı olacaktır. Bir ortanca değer, bir listenin 50. persentiline karşılık gelir:

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

Verilen listenin medyanını döndürmek için basit bir işlev:

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

kütüphane kullanmak istiyorsanız sadece yapabilirsiniz;

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

Medyan (ve persentiller) için daha genel bir yaklaşım şöyle olacaktır:

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İşlevi kullanmadan medyan bulmanın sıkıcı yolu :

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

Bu kabarcık bir çeşit mi? Neden?
Ry-

neden değerleri değiştiriyorsun?
ravi tanwar

-3

O çok basit;

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

Ve dönüş değerini şöyle kullanabilirsiniz median = median(anyList)


1
Medyan, orta noktayı bulmadan önce dizinizi sıralamanızı gerektirir.
Saurabh Jain

sListsıralı diziyi döndürür. Medyanı geri döndürmez
Farhan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.