Python 赋等级值

Python 赋等级值,下面将等级排序问题分为两部分来处理。首先创建一个通用的高阶函数给Pair对象的x或者y属性赋等级值,接着用它包装Pair对象,将xy属性的等级值纳入其中,从而避免深层嵌套结构。

为数据集中的每个样本赋等级值的函数如下所示:

from typing import Callable, Tuple, List, TypeVar, cast, Dict
from typing import Dict, Iterable, Iterator
from collections import defaultdict
D_ = TypeVar("D_")
K_ = TypeVar("K_")
def rank(
        data: Iterable[D_],
        key: Callable[[D_], K_]=lambda obj: cast(K_, obj)
    ) -> Iterator[Tuple[float, D_]]:

    def build_duplicates(
            duplicates: Dict[K_, List[D_]],
            data_iter: Iterator[D_],
            key: Callable[[D_], K_]
        ) -> Dict[K_, List[D_]]:
        for item in data_iter:
            duplicates[key(item)].append(item)
        return duplicates

    def rank_output(
            duplicates: Dict[K_, List[D_]],
            key_iter: Iterator[K_],
            base: int=0
        ) -> Iterator[Tuple[float, D_]]:
        for k in key_iter:
            dups = len(duplicates[k])
            for value in duplicates[k]:
                yield (base + 1 + base + dups) / 2, value
            base += dups

    duplicates = build_duplicates(
        defaultdict(list), iter(data), key)
    return rank_output(duplicates, iter(sorted(duplicates)), 0)

该等级排序函数使用两个子函数将值列表转换为包含序列值和源数据的二元组列表。第一步使用build_duplicates()函数创建字典duplicates,字典的键值是由源数据经key函数转换后的值,键值对应的值是由拥有相同键值的源数据组成的序列。第二步调用rank_output()函数,在duplicates的基础上生成二元组序列。

为了厘清数据之间的关系,这里定义了两个类型变量。D_类型变量代表源数据的类型,例如Leg类型或者其他复杂对象。K_类型变量代表用于排序的等级值的类型,它可以与源数据类型不同,例如从Leg命名元组中取出的距离值是实数类型。从源数据到等级值的转换是通过key参数代表的函数参数实现的,该参数的类型标示是Callable[[D_], K_]

build_duplicates()函数使用有状态的对象构造键值之间的映射关系,具体实现是通过对递归算法进行尾调用优化得到的。首先将内部状态作为build_duplicates()函数的参数暴露出来。递归的基本场景是data_iter为空,base为0。对于算法的迭代实现版本,这些变量并不是必需的,但使用它们可以更好地说明递归的工作方式。

与之类似,rank_output()函数也可以通过递归生成包含源数据和等级值的二元组,这里将其优化为二重for循环。为了显式计算出等级值,取左边界base + 1和右边界base + dups的平均值,如果duplicates的某一项只有一个元素,则等级值是(2 * base + 2) / 2,所以该公式的普适性较好。
duplicates的类型标示是Dict[K_, List[D_]],表示键类型是K_,值类型是List[D_],也就是由源数据组成的列表。这个类型在算法中多次出现,表明好的类型定义能很好地说明类型间的复用关系。

如下所示测试其能否正常工作,第一个例子是对单个值排序,第二个例子是对二元组列表排序,使用匿名函数从每组中取键值。

>>> list(rank([0.8, 1.2, 1.2, 2.3, 18]))
[(1.0, 0.8), (2.5, 1.2), (2.5, 1.2), (4.0, 2.3), (5.0, 18)]
>>> data= [(2, 0.8), (3, 1.2), (5, 1.2), (7, 2.3), (11, 18)]
>>> list(rank(data, key=lambda x:x[1]))
[(1.0, (2, 0.8)),
(2.5, (3, 1.2)),
(2.5, (5, 1.2)),
(4.0, (7, 2.3)),
(5.0, (11, 18))]

样本数据中包含了两个相同值,等级值的最终计算结果是两个顺序(2和3)的中间数2.5,这是计算两个数据集的斯皮尔曼等级相关系数的常用方法。

 rank()函数重排了输入数据以查找重复值。如果要对每一对数据的xy值求等级值,就需要对数据进行两次重排。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程