有没有办法衡量列表的排序方式?
我的意思是,它不是要知道列表是否排序(布尔值),而是类似“排序”的比例,类似于统计中的相关系数。
例如,
如果列表中的项目按升序排列,那么其费率将为1.0
如果列表按降序排序,则其速率将为-1.0
如果列表几乎按升序排序,则其速率为0.9或某个值接近1。
如果列表根本没有排序(随机),其费率将接近0
我正在Scala写一个小型图书馆进行练习。我认为排序率会很有用,但我找不到任何类似的信息。也许我不知道这个概念的适当术语。
答案 0 :(得分:141)
您只需计算列表中的反转次数即可。
T
类型元素序列中的反转是一对序列元素,它们根据<
的集合上的某些排序T
按顺序出现。< / p>
来自Wikipedia:
正式地,让
A(1), A(2), ..., A(n)
成为n
个数字序列。
如果i < j
和A(i) > A(j)
,那么(i,j)
对称为A
的反转。序列的反转数是其排序性的一个常用度量。
正式地,反转数被定义为反转次数,即
为了使这些定义更清晰,请考虑示例序列9, 5, 7, 6
。此序列包含反转 (0,1), (0,2), (0,3), (2,3)
和反转数 4
。
如果您想要0
和1
之间的值,则可以将反转数除以N choose 2
。
要实际创建一个算法来计算列表排序方式的分数,您有两种方法:
修改您喜欢的排序算法,以跟踪它在运行时纠正的反转次数。虽然这是非常重要的,并且根据您选择的排序算法具有不同的实现,但最终会得到一种算法,与您开始使用的排序算法相比,这种算法不会更复杂(在复杂性方面)。
如果采取这种方式,请注意它并不像计算“交换”那么简单。例如,Mergesort是最坏情况O(N log N)
,但如果它在按降序排序的列表上运行,它将纠正所有N choose 2
个反转。在O(N^2)
操作中纠正了O(N log N)
次反转。因此,一些操作必然会一次纠正一次以上的反转。你必须小心你的实现。 注意:您可以使用O(N log N)
复杂度执行此操作,这非常棘手。
相关:calculating the number of “inversions” in a permutation
(i,j)
,其中i != j
list[min(i,j)] < list[max(i,j)]
(0或1)N choose 2
我个人会采用随机方法,除非你有一个正确的要求 - 只是因为它很容易实现。
如果你真正想要的是z'
(按降序排序)到-1
(升序排序)之间的值(1
),你可以简单地映射上面的值({{1使用以下公式将z
(按升序排序)和0
(按降序排序)之间的值放在此范围内:
1
答案 1 :(得分:24)
对列表(或其他顺序结构)进行排序的传统方法是反转次数。
反转次数是a的对(a,b)st指数的数量。 b AND b <<
a。出于这些目的,<<
表示您为特定排序选择的任何排序关系。
完全排序的列表没有反转,完全颠倒的列表具有最大的反转次数。
答案 2 :(得分:17)
您可以使用实际相关性。
假设对于排序列表中的每个项目,您指定从零开始的整数排名。请注意,元素位置索引与排名的关系图看起来像直线上的点(位置和排名之间的相关性为1.0)。
您可以计算此数据的相关性。对于反向排序,您将获得-1,依此类推。
答案 3 :(得分:4)
有很好的答案,我想为完整性添加一个数学方面:
您可以通过衡量列表与排序列表的相关程度来衡量列表的排序方式。为此,您可以使用等级相关性(最常见的是Spearman's),这与通常的相关性完全相同,但它使用列表中的元素等级而不是其项目的模拟值
存在许多扩展,例如相关系数(精确排序为+1,精确倒置为-1)
这允许您具有此度量的统计属性,例如置换中心极限定理,它允许您了解此度量随机列表的分布。
答案 4 :(得分: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
答案 5 :(得分:1)
我不确定“最佳”方法,但一个简单的方法是将每个元素与后面的元素进行比较,如果element2&gt;则递增计数器。元素1(或任何你想测试的)然后除以元素的总数。它应该给你一个百分比。
答案 6 :(得分: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
答案 7 :(得分:0)
如果您获取列表,请计算该列表中值的排名并调用排名列表Y
和另一个列表X
,其中包含从1
到{的整数{1}},您可以通过计算两个列表之间的correlation coefficient,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
在这些限制之间因不同的排序程度而异。
这种方法可能存在的问题,取决于应用程序,计算列表中每个项目的等级等同于对其进行排序,因此它是O(n log n)操作。
答案 8 :(得分: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()