มีวิธีวัดว่าเรียงรายการอย่างไร


161

มีวิธีวัดว่าเรียงรายการอย่างไร

ฉันหมายถึงมันไม่เกี่ยวกับการรู้ว่ารายการเรียงลำดับหรือไม่ (บูลีน) แต่สิ่งที่เหมือนอัตราส่วนของ "การจัดเรียง" สิ่งที่ต้องการค่าสัมประสิทธิ์สหสัมพันธ์ในสถิติ

ตัวอย่างเช่น,

  • หากรายการของรายการอยู่ในลำดับจากนั้นอัตราจะเป็น 1.0

  • หากรายการถูกเรียงจากมากไปน้อยอัตราของมันจะเป็น -1.0

  • หากรายการเกือบเรียงจากน้อยไปมากอัตราของมันจะเป็น 0.9 หรือค่าใกล้เคียงกับ 1

  • หากไม่มีการเรียงลำดับรายการทั้งหมด (สุ่ม) อัตราจะใกล้เคียงกับ 0

ฉันกำลังเขียนห้องสมุดเล็ก ๆ ใน Scala เพื่อฝึกฝน ฉันคิดว่าอัตราการเรียงลำดับจะมีประโยชน์ แต่ฉันไม่พบข้อมูลเกี่ยวกับสิ่งนั้น บางทีฉันอาจไม่รู้เงื่อนไขที่เพียงพอสำหรับแนวคิด



4
สิ่งนี้จะถูกใช้เพื่อกำหนดอัลกอริทึมในอุดมคติเพื่อเรียงลำดับรายการ เช่นสำหรับค่าที่ใกล้เคียงกับ 0 QuickSort จะเหมาะ แต่ค่าที่ปลายทั้งสองของมาตราส่วน (เกือบเรียงหรือเกือบเรียงกลับกัน) MergeSort จะเร็วขึ้นมากเนื่องจาก QC devolves เป็น O (N ^ 2) ในกรณีเหล่านั้น
Darrel Hoffman

8
+1 สำหรับ "อัตราส่วนการเรียงลำดับ"
0x499602D2

1
@Fuhrmanator เวอร์ชัน stochastic ของอัลกอริทึมไม่จำเป็นต้องทำการเรียงลำดับเพื่อให้ได้มาถึงการประมาณความน่าจะเป็นของการเรียงลำดับ เฉพาะในกรณีที่คุณต้องการได้รับการวัดที่แน่นอนว่าคุณต้องทำการจัดเรียง
Timothy Shields

1
สัญชาตญาณแรกที่ถากถาง แต่ตลก: คุณสามารถแทรกการเรียงลำดับรายการและดูว่าต้องใช้เวลานานเท่าไรแล้วเปรียบเทียบกับระยะเวลาที่ใช้ในการเรียงลำดับรายการ (เรียงตอนนี้) และด้านหลังของรายการ
kqr

คำตอบ:


142

คุณสามารถนับจำนวนผู้รุกรานในรายการ

การผกผัน

ผกผันในลำดับขององค์ประกอบของประเภทTคือคู่ขององค์ประกอบลำดับที่ปรากฏออกคำสั่งตามที่สั่งซื้อบางส่วน<ในชุดของT's

จากWikipedia :

เป็นทางการให้A(1), A(2), ..., A(n)เป็นลำดับของnตัวเลข
ถ้าi < jและA(i) > A(j)แล้วทั้งคู่(i,j)จะเรียกว่าการผกผันAของ

จำนวนผกผันของลำดับเป็นหนึ่งในวัดที่พบบ่อยของ sortedness ของมัน
อย่างเป็นทางการหมายเลขผกผันถูกกำหนดให้เป็นจำนวนการผกผันคือ

คำนิยาม

9, 5, 7, 6เพื่อให้คำนิยามเหล่านี้ชัดเจนพิจารณาลำดับตัวอย่าง ลำดับนี้มีinversions (0,1), (0,2), (0,3), (2,3)และจำนวนผกผัน 4

หากคุณต้องการค่าระหว่าง0และคุณสามารถแบ่งจำนวนผกผันโดย1N choose 2

ในการสร้างอัลกอริทึมเพื่อคำนวณคะแนนนี้สำหรับการเรียงลำดับรายการคุณมีสองวิธี

วิธีที่ 1 (กำหนด)

ปรับเปลี่ยนอัลกอริทึมการเรียงลำดับที่คุณชื่นชอบเพื่อติดตามจำนวนผู้รุกรานที่แก้ไขเมื่อมันทำงาน แม้ว่านี่จะเป็นเรื่องไม่สำคัญและมีการใช้งานที่แตกต่างกันไปตามอัลกอริทึมการเรียงลำดับที่คุณเลือก แต่คุณจะพบกับอัลกอริทึมที่ไม่แพงมาก (ในแง่ของความซับซ้อน) กว่าอัลกอริทึมการเรียงลำดับที่คุณเริ่มต้น

หากคุณใช้เส้นทางนี้โปรดระวังว่ามันไม่ง่ายเท่ากับการนับ "สลับ" ตัวอย่างเช่นการรวมกันเป็นกรณีที่เลวร้ายที่สุดO(N log N)แต่ถ้ามันถูกเรียกใช้ในรายการเรียงตามลำดับจากมากไปน้อยมันจะแก้ไขN choose 2การรุกรานทั้งหมด นั่นคือO(N^2)การแก้ไขในO(N log N)การปฏิบัติการผกผัน ดังนั้นการดำเนินการบางอย่างจะต้องแก้ไขการผกผันมากกว่าหนึ่งครั้งอย่างหลีกเลี่ยงไม่ได้ คุณต้องระมัดระวังในการใช้งาน หมายเหตุ: คุณสามารถทำได้ด้วยO(N log N)ความซับซ้อนมันเป็นเรื่องยุ่งยาก

ที่เกี่ยวข้อง: การคำนวณจำนวนของ“ ผู้รุกราน” ในการเปลี่ยนแปลง

วิธีการ 2 (สุ่ม)

  • สุ่มคู่ตัวอย่าง(i,j)ที่ใดi != j
  • สำหรับแต่ละคู่ให้ตรวจสอบว่าlist[min(i,j)] < list[max(i,j)](0 หรือ 1)
  • คำนวณค่าเฉลี่ยของการเปรียบเทียบเหล่านี้แล้วทำให้เป็นมาตรฐานด้วย N choose 2

โดยส่วนตัวแล้วฉันจะใช้วิธีการสุ่มถ้าคุณมีความต้องการที่แน่นอน - ถ้าเพียงเพราะมันง่ายที่จะใช้


หากสิ่งที่คุณต้องการคือค่า ( z') ระหว่าง-1(เรียงจากมากไปน้อย) ถึง1(เรียงจากมากไปหาน้อย) คุณสามารถแมปค่าด้านบน ( z) ซึ่งอยู่ระหว่าง0(เรียงจากมากไปหาน้อย) และ1(เรียงจากมากไปหาน้อย) ลงในช่วงนี้โดยใช้สูตรนี้ :

z' = -2 * z + 1

2
มันเป็นเรื่องที่น่าสนใจสำหรับฉันที่การเรียงลำดับรายการคือ (โดยทั่วไป) O (n * logn) และวิธีการคำนวณแบบไร้เดียงสา / ที่เห็นได้ชัดคือ O (n ^ 2) ฉันสงสัยว่ามีอัลกอริธึมที่ดีกว่าสำหรับการคำนวณจำนวนผู้รุกรานหรือไม่?
Mark Bessey

5
มีวิธีการที่น่าสนใจสองสามข้อในคำถาม SO นี้: stackoverflow.com/questions/6523712/…โดยทั่วไปแล้วพวกเขาจะเรียงลำดับอาร์เรย์เพื่อคำนวณจำนวนผู้บุกรุกที่มี
Mark Bessey

4
ฉันคิดอย่างไร้เดียงสาว่าคุณสามารถนับคู่ที่อยู่ติดกันที่ไม่เป็นระเบียบได้ แต่นั่นจะมีค่าน้อยกว่าระดับรุนแรง: 1 2 3 1 2 3 มีการผกผันเพียงจุดเดียวติดกัน แต่กลับเป็น 50% โดยการวัดที่ถูกต้องมากกว่า
Barmar

2
@Barar ฉันคิดว่ารายการ 1 2 3 1 2 3 จะมีคุณสมบัติเป็น sorta เรียง ;-)
scunliffe

2
@ TimothyShields เอาล่ะไม่ใช่ แต่ฉันจะไม่ปฏิเสธประเด็น เพียงแค่ข้อเสนอแนะเพื่อเพิ่มคำจำกัดความที่ไม่เป็นทางการซึ่งเข้าถึงได้ง่ายสำหรับผู้ที่มีแนวโน้มน้อยกว่า
คริสคาโล

24

การวัดแบบดั้งเดิมของการเรียงลำดับรายการ (หรือโครงสร้างแบบลำดับอื่น ๆ ) คือจำนวนผู้รุกราน

จำนวนผู้รุกรานคือจำนวนคู่ (a, b) st ดัชนีของ a <b และ b <<a สำหรับวัตถุประสงค์เหล่านี้<<แสดงถึงสิ่งที่เกี่ยวข้องกับการเรียงลำดับที่คุณเลือกสำหรับการเรียงลำดับเฉพาะของคุณ

รายการที่เรียงลำดับอย่างสมบูรณ์ไม่มีการ inversions และรายการที่กลับรายการทั้งหมดมีจำนวน inversions สูงสุด


5
ในทางเทคนิค5 4 3 2 1มีการจัดเรียงอย่างสมบูรณ์เนื่องจากไม่มีการระบุคำสั่งซื้อ แต่ฉันเป็นคนที่คลั่งไคล้ :-)
paxdiablo

7
@paxdiablo <ที่ขึ้นอยู่กับความหมายของ
Marcin

@paxdiablo ดีหนึ่งสามารถวัด sortedness โดยระยะทางจากจำนวน inversions ไปยังที่อยู่ใกล้ 0 n choose 2หรือ
huon

17

คุณสามารถใช้ความสัมพันธ์ที่แท้จริง

สมมติว่าแต่ละรายการในรายการที่เรียงลำดับคุณกำหนดลำดับเลขจำนวนเต็มเริ่มจากศูนย์ โปรดทราบว่ากราฟของดัชนีตำแหน่งองค์ประกอบกับอันดับจะมีลักษณะเป็นจุดในแนวเส้นตรง (ความสัมพันธ์ของ 1.0 ระหว่างตำแหน่งและอันดับ)

คุณสามารถคำนวณสหสัมพันธ์บนข้อมูลนี้ได้ สำหรับการเรียงกลับคุณจะได้รับ -1 เป็นต้น


1
ฉันขอโทษ แต่สิ่งนี้ไม่ได้อธิบายมากเกินไปเช่นคุณกำหนดจำนวนเต็มอย่างไร
Marcin

2
คุณต้องการรายการที่เรียงลำดับเพื่อกำหนดจำนวนเต็ม; จากนั้นมันเป็นเพียงการแจงนับรายการ
Kaz

1
สิ่งที่ฉันอยากจะแนะนำ กำหนดความสัมพันธ์ระหว่างตำแหน่งของวัตถุในรายการต้นฉบับและตำแหน่งในรายการที่เรียงลำดับ ข่าวร้ายก็คือกิจวัตรความสัมพันธ์อาจจะทำงานใน O (n ^ 2); ข่าวดีก็คือพวกเขาอาจไม่ได้ขายสำหรับสภาพแวดล้อมของคุณ
Peter Webb

2
ใช่เพียงแค่ rho en.wikipedia.org/wiki/…
ลูคัส

ฉันอยากรู้อยากเห็น ... วิธีนี้เทียบเท่ากับการปรับจำนวนการนับของผู้รุกรานหรือไม่
Clayton Stanley

4

มีคำตอบที่ดีมากและฉันอยากจะเพิ่มแง่มุมทางคณิตศาสตร์เพื่อความสมบูรณ์:

  • คุณสามารถวัดได้ว่ารายการเรียงลำดับอย่างไรโดยการวัดว่ามีความสัมพันธ์กับรายการที่เรียงลำดับมากแค่ไหน ในการทำเช่นนั้นคุณอาจใช้อันดับความสัมพันธ์ (ที่รู้จักกันมากที่สุดว่าเป็นSpearman's ) ซึ่งเหมือนกับความสัมพันธ์ปกติ แต่ใช้อันดับขององค์ประกอบในรายการแทนค่าแอนะล็อกของรายการ

  • มีส่วนขยายจำนวนมากเช่นค่าสัมประสิทธิ์สหสัมพันธ์(+1 สำหรับการเรียงลำดับที่แน่นอน -1 สำหรับการกลับรายการที่แน่นอน)

  • สิ่งนี้ช่วยให้คุณมีคุณสมบัติทางสถิติสำหรับการวัดนี้เช่นทฤษฎีการ จำกัด การเรียงสับเปลี่ยนที่อนุญาตให้คุณรู้การกระจายตัวของการวัดนี้สำหรับรายการแบบสุ่ม


3

นอกเหนือจากการนับผกผันสำหรับรายการที่เป็นตัวเลขหมายถึงระยะห่างจากการเรียงลำดับของรัฐเรียงเป็นภาพ:

#! ruby
d = -> a { a.zip( a.sort ).map { |u, v| ( u - v ) ** 2 }.reduce( :+ ) ** 0.5 }

a = 8, 7, 3, 4, 10, 9, 6, 2, 5, 1
d.( a ) #=> 15.556
d.( a.sort ) #=> 0.0
d.( a.sort.reverse ) # => 18.166 is the worrst case

ผมคิดว่าตารางการทำงานของความสัมพันธ์มาตรฐานให้ดูen.wikipedia.org/wiki/Correlation_ratio และนำไปใช้อย่างเท่าเทียมกันกับรายการที่ไม่ใช่ตัวเลข ค่าสองค่าที่ถูกเปรียบเทียบคือตำแหน่งของวัตถุในสองรายการ
Peter Webb

ฉันเป็นคนเรียบง่าย ฉันไม่รู้ด้วยซ้ำว่าอัตราส่วนความสัมพันธ์คืออะไร เมื่อฉันอ่านบทความ Wikipedia ที่ด้านบนสุดฉันขอให้เรียนรู้ว่า "การกระจายเชิงสถิติ" คืออะไรจากนั้น "ค่าเบี่ยงเบนมาตรฐาน" จากนั้น "การเปลี่ยนแปลง" จากนั้น "ค่าสัมประสิทธิ์สหสัมพันธ์ระหว่าง" ฉันเรียนรู้สิ่งเหล่านั้นหลายครั้งและหลายครั้งฉันลืมมันอีกครั้ง ในคำตอบเชิงปฏิบัติของฉันฉันแค่วัดระยะทางระหว่างเวกเตอร์สองตัวกับทฤษฎีบทพีทาโกรัสที่ฉันจำได้จากโรงเรียนประถมนั่นคือทั้งหมด
Boris Stitnicky

1

ฉันไม่แน่ใจเกี่ยวกับวิธีที่ "ดีที่สุด" แต่วิธีที่ง่าย ๆ คือการเปรียบเทียบทุกองค์ประกอบกับหนึ่งหลังจากนั้นเพิ่มตัวนับถ้า element2> องค์ประกอบ 1 (หรือสิ่งที่คุณต้องการทดสอบ) แล้วหารด้วยจำนวนทั้งหมด ขององค์ประกอบ ควรให้เปอร์เซ็นต์


1

ฉันจะนับการเปรียบเทียบและหารด้วยจำนวนการเปรียบเทียบทั้งหมด นี่คือตัวอย่างของPython

my_list = [1,4,5,6,9,-1,5,3,55,11,12,13,14]

right_comparison_count = 0

for i in range(len(my_list)-1):
    if my_list[i] < my_list[i+1]: # Assume you want to it ascending order
        right_comparison_count += 1

if right_comparison_count == 0:
    result = -1
else:
    result = float(right_comparison_count) / float((len(my_list) - 1))

print result

0

แล้วเรื่องแบบนี้ล่ะ?

#!/usr/bin/python3

def sign(x, y):
   if x < y:
      return 1
   elif x > y:
      return -1
   else:
      return 0

def mean(list_):
   return float(sum(list_)) / float(len(list_))

def main():
   list_ = [ 1, 2, 3, 4, 6, 5, 7, 8 ]
   signs = []
   # this zip is pairing up element 0, 1, then 1, 2, then 2, 3, etc...
   for elem1, elem2 in zip(list_[:-1], list_[1:]):
      signs.append(sign(elem1, elem2))

   # This should print 1 for a sorted list, -1 for a list that is in reverse order
   # and 0 for a run of the same numbers, like all 4's
   print(mean(signs))

main()

2
สิ่งนี้นับเฉพาะการรุกรานที่อยู่ติดกัน หากคุณดูคำตอบอื่น ๆ คุณจะเห็นว่านี่ไม่เพียงพอ
Konrad Rudolph

1
@ KonradRudolph: ฉันคิดว่าคำตอบนี้ตอบสนองคำถามที่ถาม ความจริงที่ว่าคำตอบอื่น ๆ นั้นครอบคลุมมากขึ้นไม่ได้หมายความว่าคำตอบนี้ไม่เพียงพอ มันขึ้นอยู่กับข้อกำหนดของ OP
LarsH

0

หากคุณใช้รายการของคุณให้คำนวณอันดับของค่าในรายการนั้นและเรียกรายการลำดับYและรายการอื่นXที่มีจำนวนเต็มจาก1ถึงlength(Y)คุณสามารถรับการวัดความเรียงที่คุณกำลังมองหาโดยการคำนวณสัมประสิทธิ์สหสัมพันธ์ ,, rระหว่างสองรายการ

r = \frac{\sum ^n _{i=1}(X_i - \bar{X})(Y_i - \bar{Y})}{\sqrt{\sum ^n _{i=1}(X_i - \bar{X})^2} \sqrt{\sum ^n _{i=1}(Y_i - \bar{Y})^2}} 

สำหรับรายการที่จัดเรียงอย่างสมบูรณ์สำหรับรายการที่เรียงลำดับr = 1.0ย้อนกลับr=-1.0และrแตกต่างกันระหว่างขีด จำกัด เหล่านี้สำหรับองศาการแตกต่างกัน

ปัญหาที่เป็นไปได้กับวิธีนี้ขึ้นอยู่กับแอปพลิเคชันคือการคำนวณอันดับของแต่ละรายการในรายการนั้นเทียบเท่ากับการเรียงลำดับดังนั้นจึงเป็นการดำเนินการ O (n log n)


แต่นั่นจะไม่เพิกเฉยต่อรูปร่างโค้ง ถ้าอาเรย์ของเขาถูกเรียงลำดับ แต่พูดว่ามีค่าที่เพิ่มขึ้นแบบเอกซ์โปเนนชันความสัมพันธ์จะมีค่าน้อยซึ่งเขาต้องการให้มันเป็น 1.0
Lee Daniel Crocker

@LeeDanielCrocker: ใช่นั่นเป็นจุดที่ดี ฉันแก้ไขคำตอบของฉันเพื่อแก้ไขปัญหานี้โดยการจัดอันดับของค่าต่างๆ
Simon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.